Sequence Containers

Implement data structures which can be accessed in a sequential manner

std::vector

template < class T, class Alloc = allocator > class vector;
header

Member function

begin
end
rbegin Return reverse iterator to reverse beginning
rend Return reverse iterator to reverse end
cbegin
cend
crbegin
crend
size
max_size Return maximum size
resize
capacity
empty
reserve
erase iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);
myvec.erase(myvector.begin() + 5)
myvec.erase(myvector.begin(), myvector.begin() + 5)
operator[] Access element
at Access element
front Access first element
back Access last element
data
assign
push_back Add element at the end
pop_back Delete last element
insert iterator insert(const_iterator position, const value_type& val); Insert elements
swap void swap (vector& x); Swap content
std::vectorfoo(3,100);
std::vectorbar(5,200);
foo.swap(bar);
clear Clear content
  1. // inserting into a vector
  2. #include <iostream>
  3. #include <vector>
  4. int main ()
  5. {
  6. std::vector<int> myvector (3,100);
  7. std::vector<int>::iterator it;
  8. it = myvector.begin();
  9. it = myvector.insert ( it , 200 );
  10. myvector.insert (it,2,300);
  11. // "it" no longer valid, get a new one:
  12. it = myvector.begin();
  13. std::vector<int> anothervector (2,400);
  14. myvector.insert (it+2,anothervector.begin(),anothervector.end());
  15. int myarray [] = { 501,502,503 };
  16. myvector.insert (myvector.begin(), myarray, myarray+3);
  17. std::cout << "myvector contains:";
  18. for (it=myvector.begin(); it<myvector.end(); it++)
  19. std::cout << ' ' << *it;
  20. std::cout << '\n';
  21. return 0;
  22. }
  23. //myvector contains: 501 502 503 300 300 400 400 200 100 100 100

Container Adaptors

Provide a different interface for sequential containers

std::queue

template > class queue;
header

Member functions

empty bool empty() const; Test whether container is empty
Returns whether the queue is empty: i.e. whether its size is zero.
size size_type size() const; Return size
Returns the number of elements in the queue.
front reference& front();
const_reference& front() const;
Access next element
Returns a reference to the next element in the queue.
The next element is the “oldest” element in the queue and the same element that is popped out from the queue when queue::pop is called.
back value_type& back();
const value_type& back() const;
Access last element
Returns a reference to the last element in the queue. This is the “newest” element in the queue (i.e. the last element pushed into the queue).
push void push (const value_type& val);
void push (value_type&& val);
Insert element
Inserts a new element at the end of the queue, after its current last element. The content of this new element is initialized to val.
emplace templatevoid emplace(Args&&… args); Construct and insert element
Adds a new element at the end of the queue, after its current last element. This new element is constructed in place passing args as the arguments for its constructor.
pop void pop(); Remove next element
Removes the next element in the queue, effectively reducing its size by one.
The element removed is the “oldest” element in the queue whose value can be retrieved by calling member queue::front.

This calls the removed element’s destructor.
swap void swap (queue& x) noexcept(/see below/) Swap contents
Exchanges the contents of the container adaptor (*this) by those of x.
This member function calls the non-member function swap (unqualified) to swap the underlying containers.

Example

// CPP code to illustrate  
// Queue in Standard Template Library (STL) 
#include <iostream> 
#include <queue> 

using namespace std; 

void showq(queue <int> gq) 
{ 
    queue <int> g = gq; 
    while (!g.empty()) 
    { 
        cout << '\t' << g.front(); 
        g.pop(); 
    } 
    cout << '\n'; 
} 

int main() 
{ 
    queue <int> gquiz; 
    gquiz.push(10); 
    gquiz.push(20); 
    gquiz.push(30); 

    cout << "The queue gquiz is : "; 
    showq(gquiz); 

    cout << "\ngquiz.size() : " << gquiz.size(); 
    cout << "\ngquiz.front() : " << gquiz.front(); 
    cout << "\ngquiz.back() : " << gquiz.back(); 

    cout << "\ngquiz.pop() : "; 
    gquiz.pop(); 
    showq(gquiz); 

    return 0; 
}

std::stack

header
template > class stack;

Member Functions

empty
size
top
push
emplace
pop
swap

std::greater

<functional>

template <class T> struct greater {
    bool operator() (const T& x, const T& y) const {return x > y};
    typedef T first_agrument_type;
    typedef T second_agrument_type;
    typedef bool result_type;
};

std::less

<functional>

template <class T>
    struct less{
        bool operator() (const T& x, const T& y) const {return x < y;}
        typedef T first_argument_type;
        typedef T second_argument_type;
        typedef bool result_tyope;
    };

std::priority_queue

默认情况下是最大堆

<queue>

template <class T, class Container = vector<T>,
    class Compare = less<typename Container::value_type>> class priority_queue;
empty
size
top
push
pop
swap
#include <iostream>
#include <queue>

using namespace std;

void showpq(priority_queue<int> gq)
{
    priority_queue<int> g= gq;
    while (!g.empty())
    {
        cout << "\t" << g.top();
        g.pop();
    }
    cout << "\n";
}

int main()
{
    priority_queue<int> gquiz;
    gquiz.push(10);
    gquiz.push(30);
    gquiz.push(20);
    gquiz.push(5);
    gquiz.push(1);

    cout << "The priority queue gquiz is: ";
    showpq(gquiz);

    cout << "\ngquize.size(): " << gquiz.size();
    cout << "\ngquize.top(): " << gquiz.top();

    cout << "\ngquiz.pop() :";
    gquiz.pop();
    showpq(gquiz);

    return 0;
}

创建最小堆

// C++ program to demonstrate min heap
#include <iostream>
#include <queue>

using namespace std;

void showpq(
    priority_queue<int, vector<int>, greater<int> > gq)
{
    priority_queue<int, vector<int>, 
                                greater<int> > g = gq;
    while (!g.empty()) {
        cout << '\t' << g.top();
        g.pop();
    }
    cout << '\n';
}

int main()
{
    priority_queue<int, vector<int>,  
                       greater<int> > gquiz;
    gquiz.push(10);
    gquiz.push(30);
    gquiz.push(20);
    gquiz.push(5);
    gquiz.push(1);

    cout << "The priority queue gquiz is : ";
    showpq(gquiz);

    cout << "\ngquiz.size() : " << gquiz.size();
    cout << "\ngquiz.top() : " << gquiz.top();

    cout << "\ngquiz.pop() : ";
    gquiz.pop();
    showpq(gquiz);

    return 0;
}

Associative Containers

Implement sorted data structures that can be quickly searched(O(log n) complexity)

std::map

header
template < class Key, // map::key_type
class T, // map::mapped_type
class Compare = less, // map::key_compare
class Alloc = allocator > // map::allocator_type
> class map;

Member Functions

begin
end
rbegin
rend
cbegin
cend
crbegin
crend
empty
size
max_size
operator[]
at
insert
erase iterator erase (const_iterator position);
size_type erase (const key_type& k);
iterator erase (const_iterator first, const_iterator last);
std::mapmymap;
mymap[‘a’]=10
it=mymap.find(‘a’)
mymap.erase(it)
mymap.erase(‘a’)
mymap.erase(it, mymap.end())
swap
clear
key_comp
value_comp
find
count
lower_bound
upper_bound
upper_bound
equal_range

map的坑

void function(const map &mymap)
{
  std::string value = mymap["string"];
  // By doing so I am getting an error.
}

由于 std::map::operator[] 是非常量成员函数,而 const map &mymap 采用的是常引用,因此会报错
解决办法之一是不使用常引用 map mymap

Unfortunately std::map::operator[] is a non-const member function, and you have a const reference.

另外的解决办法是

MAP::const_iterator pos = map.find("string");
if (pos == map.end()) {
    //handle the error
} else {
    std::string value = pos->second;
    ...
}

operator[] handles the error by adding a default-constructed value to the map and returning a reference to it. This is no use when all you have is a const reference, so you will need to do something different. You could ignore the possibility and write string value = map.find("string")->second;, if your program logic somehow guarantees that "string" is already a key. The obvious problem is that if you’re wrong then you get undefined behavior.

https://stackoverflow.com/questions/10699689/how-can-i-get-a-value-from-a-map

std::set

header
template < class T, // set::key_type/value_type
class Compare = less, // set::key_compare/value_compare
class Alloc = allocator // set::allocator_type
> class set;

Member Functions

Unordered Associative Containers

implement unordered data structures that can be quickly searched

unordered_map

header
template >

unordered_set

这里需要注意的是unordered_set只是按照哈希值进行存储,不是按照特定的顺序进行存储,这也就意味着,它不是按照插入的顺序进行排序的。千万不要将它作为排序序列进行存储

Internally, the elements in the unordered_set are not sorted in any particular order, but organized into buckets depending on their hash values to allow for fast access to individual elements directly by their values (with a constant average time complexity on average).

<unordered_set>

std::unordered_set

template<class Key,
         class Hash = hash<Key>,           // unordered_set::hasher
         class Pred = equal_to<Key>,       // unordered_set::key_equal
         class Alloc = allocator<Key>      // unordered_set::allocator_type
         > 
class unordered_set;

std::unordered_set::erase
iterator erase ( const_iterator position ); //by position (1)    
size_type erase ( const key_type& k ); //by key (2)    
iterator erase ( const_iterator first, const_iterator last ); //range (3)

std::unordered_set::find
iterator find ( const key_type& k );
const_iterator find ( const key_type& k ) const;

unordered_map

unordered_multimap

Algorithm

std::sort

header <algorithm>
template <class RandomAccessIterator>void sort (RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

sort(first_iterator, last_iterator)

// sort algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector

bool myfunction (int i,int j) { return (i<j); }

struct myclass {
  bool operator() (int i,int j) { return (i<j);}
} myobject;

int main () {
  int myints[] = {32,71,12,45,26,80,53,33};
  std::vector<int> myvector (myints, myints+8);               // 32 71 12 45 26 80 53 33

  // using default comparison (operator <):
  std::sort (myvector.begin(), myvector.begin()+4);           //(12 32 45 71)26 80 53 33

  // using function as comp
  std::sort (myvector.begin()+4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)

  // using object as comp
  std::sort (myvector.begin(), myvector.end(), myobject);     //(12 26 32 33 45 53 71 80)

  // print out content:
  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

//output
//$ myvector contains: 12 26 32 33 45 53 71 80

std::reverse

To reverse a vector
header
reverse(first_iterator, last_iterator)

// A C++ program to demonstrate working of sort(), 
// reverse() 
#include <algorithm> 
#include <iostream> 
#include <vector> 
using namespace std; 

int main() 
{ 
    // Initializing vector with array values 
    int arr[] = {10, 20, 5, 23 ,42 , 15}; 
    int n = sizeof(arr)/sizeof(arr[0]); 
    vector<int> vect(arr, arr+n); 

    cout << "Vector is: "; 
    for (int i=0; i<n; i++) 
        cout << vect[i] << " "; 

    // Reversing the Vector 
    reverse(vect.begin(), vect.end()); 

    cout << "\nVector after reversing is: "; 
    for (int i=0; i<6; i++) 
        cout << vect[i] << " "; 

    return 0; 
}

abs

<cstdlib>

int abs(int n);
long int abs(long int n);
long long int abs(long long int n);

std::max_element

To find the maximum element of a vector.
header
*max_element(first_iterator, last_iterator)

// A C++ program to demonstrate working of sort(), 
// reverse() 
#include <algorithm> 
#include <iostream> 
#include <vector> 
using namespace std; 

int main() 
{ 
    // Initializing vector with array values 
    int arr[] = {10, 20, 5, 23 ,42 , 15}; 
    int n = sizeof(arr)/sizeof(arr[0]); 
    vector<int> vect(arr, arr+n); 

    cout << "Vector is: "; 
    for (int i=0; i<n; i++) 
        cout << vect[i] << " "; 

    cout << "\nMaximum element of vector is: "; 
    cout << *max_element(vect.begin(), vect.end()); 

    return 0; 
}

std::min

<algorithm>

template <class T> const T& min(const T& a, const T& b);
template <class T, class Compare>
        const T& min(const T& a, const T& b, Compare comp);
template <class T, class Compare>
        T min(initializer_list<T> il, Compare comp);

std::min_element

To find the minimum element of a vector
header
*min_element(first_iterator, last_iterator)

// A C++ program to demonstrate working of sort(), 
// reverse() 
#include <algorithm> 
#include <iostream> 
#include <vector> 
using namespace std; 

int main() 
{ 
    // Initializing vector with array values 
    int arr[] = {10, 20, 5, 23 ,42 , 15}; 
    int n = sizeof(arr)/sizeof(arr[0]); 
    vector<int> vect(arr, arr+n); 

    cout << "Vector is: "; 
    for (int i=0; i<n; i++) 
        cout << vect[i] << " "; 

    cout << "\nMinimum element of vector is: "; 
    cout << *min_element(vect.begin(), vect.end()); 

    return 0; 
}

std::none_of

<algorithm>

template< class InputIt, class UnaryPredicate >
bool none_of( InputIt first, InputIt last, UnaryPredicate p );

template< class InputIt, class UnaryPredicate >
constexpr bool none_of( InputIt first, InputIt last, UnaryPredicate p );

template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
bool none_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPredicate p );
template< class InputIt, class UnaryPredicate >
constexpr bool all_of(InputIt first, InputIt last, UnaryPredicate p)
{
    return std::find_if_not(first, last, p) == last;
}

template< class InputIt, class UnaryPredicate >
constexpr bool any_of(InputIt first, InputIt last, UnaryPredicate p)
{
    return std::find_if(first, last, p) != last;
}

template< class InputIt, class UnaryPredicate >
constexpr bool none_of(InputIt first, InputIt last, UnaryPredicate p)
{
    return std::find_if(first, last, p) == last;
}
#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <functional>

int main()
{
    std::vector<int> v(10, 2);
    std::partial_sum(v.cbegin(), v.cend(), v.begin());
    std::cout << "Among the numbers: ";
    std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    if (std::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; })) {
        std::cout << "All numbers are even\n";
    }
    if (std::none_of(v.cbegin(), v.cend(), std::bind(std::modulus<int>(), 
                                                     std::placeholders::_1, 2))) {
        std::cout << "None of them are odd\n";
    }
    struct DivisibleBy
    {
        const int d;
        DivisibleBy(int n) : d(n) {}
        bool operator()(int n) const { return n % d == 0; }
    };

    if (std::any_of(v.cbegin(), v.cend(), DivisibleBy(7))) {
        std::cout << "At least one number is divisible by 7\n";
    }
}

std::distance

header <iterator>

//Calculates the number of elements between first and last.
std::distance
template<class InputIterator>
    typename iterator_traits<InputIterator>::difference_type
        distance(InputIterator first, InputIterator last);

//Example
// advance example
#include <iostream>     // std::cout
#include <iterator>     // std::distance
#include <list>         // std::list

int main () {
  std::list<int> mylist;
  for (int i=0; i<10; i++) mylist.push_back (i*10);

  std::list<int>::iterator first = mylist.begin();
  std::list<int>::iterator last = mylist.end();

  std::cout << "The distance is: " << std::distance(first,last) << '\n';

  return 0;
}

std::find

<algorithm>

template <class InputIterator, class T>
   InputIterator find (InputIterator first, InputIterator last, const T& val);

// find example
#include <iostream>     // std::cout
#include <algorithm>    // std::find
#include <vector>       // std::vector

int main () {
  // using std::find with array and pointer:
  int myints[] = { 10, 20, 30, 40 };
  int * p;

  p = std::find (myints, myints+4, 30);
  if (p != myints+4)
    std::cout << "Element found in myints: " << *p << '\n';
  else
    std::cout << "Element not found in myints\n";

  // using std::find with vector and iterator:
  std::vector<int> myvector (myints,myints+4);
  std::vector<int>::iterator it;

  it = find (myvector.begin(), myvector.end(), 30);
  if (it != myvector.end())
    std::cout << "Element found in myvector: " << *it << '\n';
  else
    std::cout << "Element not found in myvector\n";

  return 0;
}

// Result
Element found in myints: 30
Element found in myvector: 30

std::less

template <class T> struct less {
  bool operator() (const T& x, const T& y) const {return x<y;}
  typedef T first_argument_type;
  typedef T second_argument_type;
  typedef bool result_type;
};

std::unique

unique能够移除当前元素的后面与其相邻的重复元素移除,它不会移除其后面的与其不相邻的重复元素,最后返回的是新区间的尾端。


template <class ForwardIterator>
  ForwardIterator unique (ForwardIterator first, ForwardIterator last);

template <class ForwardIterator, class BinaryPredicate>
  ForwardIterator unique (ForwardIterator first, ForwardIterator last,
                          BinaryPredicate pred);
// unique algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::unique, std::distance
#include <vector>       // std::vector

bool myfunction (int i, int j) {
  return (i==j);
}

int main () {
  int myints[] = {10,20,20,20,30,30,20,20,10};           // 10 20 20 20 30 30 20 20 10
  std::vector<int> myvector (myints,myints+9);

  // using default comparison:
  std::vector<int>::iterator it;
  it = std::unique (myvector.begin(), myvector.end());   // 10 20 30 20 10 ?  ?  ?  ?
                                                         //                ^

  myvector.resize( std::distance(myvector.begin(),it) ); // 10 20 30 20 10

  // using predicate comparison:
  std::unique (myvector.begin(), myvector.end(), myfunction);   // (no changes)

  // print out content:
  std::cout << "myvector contains:";
  for (it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

unique实现

template<class ForwardIterator>
ForwardIterator unique(ForwardIterator first, ForwardIterator last) {
    first = adjacent_find(first, last);
    return unique_copy(first ,last, first);
}

lower_bound

返回一个迭代器,表示第一个小于等于val的元素,如果不存在这样的元素,则返回end

template< class ForwardIt, class T >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value );
(until C++20)
template< class ForwardIt, class T >
constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value );
(since C++20)
(2)    
template< class ForwardIt, class T, class Compare >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );
(until C++20)
template< class ForwardIt, class T, class Compare >
constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );
(since C++20)
template<class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first, last);

    while (count > 0) {
        it = first; 
        step = count / 2; 
        std::advance(it, step);
        if (*it < value) {
            first = ++it; 
            count -= step + 1; 
        }
        else
            count = step;
    }
    return first;
}
template<class ForwardIt, class T, class Compare>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first, last);

    while (count > 0) {
        it = first;
        step = count / 2;
        std::advance(it, step);
        if (comp(*it, value)) {
            first = ++it;
            count -= step + 1;
        }
        else
            count = step;
    }
    return first;
}
#include <algorithm>
#include <iostream>
#include <vector>

struct PriceInfo { double price; };

int main()
{
    const std::vector<int> data = { 1, 2, 4, 5, 5, 6 };
    for (int i = 0; i < 8; ++i) {
        // Search for first element x such that i ≤ x
        auto lower = std::lower_bound(data.begin(), data.end(), i);

        std::cout << i << " ≤ ";
        lower != data.end()
            ? std::cout << *lower << " at index " << std::distance(data.begin(), lower)
            : std::cout << "[not found]";
        std::cout << '\n';
    }

    std::vector<PriceInfo> prices = { {100.0}, {101.5}, {102.5}, {102.5}, {107.3} };
    for(double to_find: {102.5, 110.2}) {
      auto prc_info = std::lower_bound(prices.begin(), prices.end(), to_find,
          [](const PriceInfo& info, double value){
              return info.price < value;
          });

      prc_info != prices.end()
          ? std::cout << prc_info->price << " at index " << prc_info - prices.begin()
          : std::cout << to_find << " not found";
      std::cout << '\n';
    }
}

//Result
0 ≤ 1 at index 0
1 ≤ 1 at index 0
2 ≤ 2 at index 1
3 ≤ 4 at index 2
4 ≤ 4 at index 2
5 ≤ 5 at index 3
6 ≤ 6 at index 5
7 ≤ [not found]
102.5 at index 2
110.2 not found

upper_bound

返回一个迭代器,表示第一个大于等于val的元素,如果不存在这样的元素,则返回end

equal_range

返回一个pair,其first成员是lower_bound返回的迭代器,second成员是upper_bound返回的迭代器

binary_search

返回一个bool值,指出序列中是否包含等于val的元素。对于两个值x和y,当x不小于y且y也不小于x时,认为他们是相等的。

default (1)    
template <class ForwardIterator, class T>
  bool binary_search (ForwardIterator first, ForwardIterator last,
                      const T& val);
custom (2)    
template <class ForwardIterator, class T, class Compare>
  bool binary_search (ForwardIterator first, ForwardIterator last,
                      const T& val, Compare comp);



template <class ForwardIterator, class T>
  bool binary_search (ForwardIterator first, ForwardIterator last, const T& val)
{
  first = std::lower_bound(first,last,val);
  return (first!=last && !(val<*first));
}

swap

template< class T >
void swap( T& a, T& b );
(until C++11)
template< class T >
void swap( T& a, T& b ) noexcept(/* see below */);
(since C++11)
(until C++20)
template< class T >
constexpr void swap( T& a, T& b ) noexcept(/* see below */);
(since C++20)
(2)    
template< class T2, std::size_t N >
void swap( T2 (&a)[N], T2 (&b)[N]) noexcept(/* see below */);
(since C++11)
(until C++20)
template< class T2, std::size_t N >
constexpr void swap( T2 (&a)[N], T2 (&b)[N]) noexcept(/* see below */);
#include <algorithm>
#include <iostream>

int main()
{
    int a = 5, b = 3;

    // before
    std::cout << a << ' ' << b << '\n';

    std::swap(a,b);

    // after
    std::cout << a << ' ' << b << '\n';
}

//Output
5 3
3 5

Smart Pointers

智能指针在C/C++的重要性

Pointers are used for accessing the resources which are external to the program like heap memory. So for accessing the heap memory if anything is created inside heap memory Pointers are used.

普通指针的缺陷

#include <iostream> 
using namespace std; 

class Rectangle { 
private: 
    int length; 
    int breadth; 
}; 

void fun() 
{ 
    // By taking a pointer p and 
    // dynamically creating object 
    // of class rectangle 
    Rectangle* p = new Rectangle(); 
} 

int main() 
{ 
    // Infinite Loop 
    while (1) { 
        fun(); 
    } 
}

在这里p是局部变量,因此将不再可能释放以前p所指向的空间,在无限循环中,最终会因为内存的严重泄漏而导致程序崩溃。

智能指针

当object在跳出其作用域之后,会自动调用其析构函数,由析构函数自动的完成资源的释放。一个简单的实现方式如下

#include <iostream> 
using namespace std; 

class SmartPtr { 
    int* ptr; // Actual pointer 
public: 
    // Constructor: Refer https:// www.geeksforgeeks.org/g-fact-93/ 
    // for use of explicit keyword 
    explicit SmartPtr(int* p = NULL) { ptr = p; } 

    // Destructor 
    ~SmartPtr() { delete (ptr); } 

    // Overloading dereferencing operator 
    int& operator*() { return *ptr; } 
}; 

int main() 
{ 
    SmartPtr ptr(new int()); 
    *ptr = 20; 
    cout << *ptr; 

    // We don't need to call delete ptr: when the object 
    // ptr goes out of scope, the destructor for it is automatically 
    // called and destructor does delete ptr. 

    return 0; 
}

下面是也给针对所有类型的简单实现

#include <iostream> 
using namespace std; 

// A generic smart pointer class 
template <class T> 
class SmartPtr { 
    T* ptr; // Actual pointer 
public: 
    // Constructor 
    explicit SmartPtr(T* p = NULL) { ptr = p; } 

    // Destructor 
    ~SmartPtr() { delete (ptr); } 

    // Overloading dereferncing operator 
    T& operator*() { return *ptr; } 

    // Overloading arrow operator so that 
    // members of T can be accessed 
    // like a pointer (useful if T represents 
    // a class or struct or union type) 
    T* operator->() { return ptr; } 
}; 

int main() 
{ 
    SmartPtr<int> ptr(new int()); 
    *ptr = 20; 
    cout << *ptr; 
    return 0; 
}

unique_ptr

If you are using a unique pointer then if one object is created and pointer P1 is pointing to this one them only one pointer can point this one at one time. So we can’t share with another pointer, but we can transfer the control to P2 by removing P1.

#include <iostream> 
using namespace std; 
#include <memory> 

class Rectangle { 
    int length; 
    int breadth; 

public: 
    Rectangle(int l, int b) 
    { 
        length = l; 
        breadth = b; 
    } 

    int area() 
    { 
        return length * breadth; 
    } 
}; 

int main() 
{ 

    unique_ptr<Rectangle> P1(new Rectangle(10, 5)); 
    cout << P1->area() << endl; // This'll print 50 

    // unique_ptr<Rectangle> P2(P1); 

    unique_ptr<Rectangle> P2; 
    P2 = move(P1); 

    // This'll print 50 
    cout << P2->area() << endl; 

    // cout<<P1->area()<<endl; 
    return 0; 
}

shared_ptr

If you are using shared_ptr then more than one pointer can point to this one object at a time and it’ll maintain a Reference Counter using use_count() method.
Class shared_ptr 实现共享式拥有(shared ownership)概念。多个智能指针指向相同对象,该对象和其相关资源会在 “最后一个 reference 被销毁” 时被释放。对象的最末一个拥有着有责任销毁对象,并清理与该对象相关的所有资源。
支持定制型删除器(custom deleter),可防范 Cross-DLL 问题(对象在动态链接库(DLL)中被 new 创建,却在另一个 DLL 内被 delete 销毁)、自动解除互斥锁
C++标准保证了西沟函数对“强引用计数”无data race,故而他会被安全地逐个减1,并最终在导致减到0的那个线程上析构被分享的对象。

#include <iostream> 
using namespace std; 
#include <memory> 

class Rectangle { 
    int length; 
    int breadth; 

public: 
    Rectangle(int l, int b) 
    { 
        length = l; 
        breadth = b; 
    } 

    int area() 
    { 
        return length * breadth; 
    } 
}; 

int main() 
{ 

    shared_ptr<Rectangle> P1(new Rectangle(10, 5)); 
    // This'll print 50 
    cout << P1->area() << endl; 

    shared_ptr<Rectangle> P2; 
    P2 = P1; 

    // This'll print 50 
    cout << P2->area() << endl; 

    // This'll now not give an error, 
    cout << P1->area() << endl; 

    // This'll also print 50 now 
    // This'll print 2 as Reference Counter is 2 
    cout << P1.use_count() << endl; 
    return 0; 
}

weak_ptr

It’s much more similar to shared_ptr except it’ll not maintain a Reference Counter.In this case, a pointer will not have a strong hold on the object. The reason is if suppose pointers are holding the object and requesting for other objects then they may form a Deadlock.
Class unique_ptr 实现独占式拥有(exclusive ownership)或严格拥有(strict ownership)概念,保证同一时间内只有一个智能指针可以指向该对象。你可以移交拥有权。它对于避免内存泄漏(resource leak)——如 new 后忘记 delete ——特别有用。

Others

std::bitset

header
template class bitset;

Member Functions

operator[] Access Bits
count Count bits set
size Return size
test Return bit value
any Test if any bit is set
none Test if no bit is set
all Test if all bits are set
set Set bits
reset Reset bits
flip Flip bits
to_string Convert to string
to_ulong Convert to unsigned long integer
to_ullong Convert to unsigned long long
// bitset::operator[]
#include <iostream>       // std::cout
#include <bitset>         // std::bitset

int main ()
{
  std::bitset<4> foo;

  foo[1]=1;             // 0010
  foo[2]=foo[1];        // 0110

  std::cout << "foo: " << foo << '\n';

  return 0;
}

rand

int rand(void)
header

Returns a pseudo-random integral number in the range between 0 and RAND_MAX.

v1 = rand() % 100; // v1 in the range 0 to 99
v2 = rand() % 100 + 1; // v2 in the range 1 to 100
v3 = rand() % 30 + 1985; // v3 in the range 1985-2014

/* rand example: guess the number */
#include <stdio.h>      /* printf, scanf, puts, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */

int main ()
{
  int iSecret, iGuess;

  /* initialize random seed: */
  srand (time(NULL));

  /* generate secret number between 1 and 10: */
  iSecret = rand() % 10 + 1;

  do {
    printf ("Guess the number (1 to 10): ");
    scanf ("%d",&iGuess);
    if (iSecret<iGuess) puts ("The secret number is lower");
    else if (iSecret>iGuess) puts ("The secret number is higher");
  } while (iSecret!=iGuess);

  puts ("Congratulations!");
  return 0;
}

/*
    Guess the number (1 to 10): 5
    The secret number is higher
    Guess the number (1 to 10): 8
    The secret number is lower
    Guess the number (1 to 10): 7
    Congratulations!
*/

std::uniform_int_distribution

header
Produces random integer values i, uniformly distributed on the closed interval [a, b], that is, distributed according to the discrete probability function
C   STL - 图1
std::uniform_int_distribution satisfies all requirements of RandomNumberDistribution

#include <random>
#include <iostream>

int main()
{
    std::random_device rd;  //Will be used to obtain a seed for the random number engine
    std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
    std::uniform_int_distribution<> distrib(1, 6);

    for (int n=0; n<10; ++n)
        //Use `distrib` to transform the random unsigned int generated by gen into an int in [1, 6]
        std::cout << distrib(gen) << ' ';
    std::cout << '\n';
}

// 1 1 6 5 2 2 5 5 6 2

std::bind

header

The function template bind generates a forwarding call wrapper for f. Calling this wrapper is equivalent to invoking f with some of its arguments bound to args.

template bind(F&& f, Args&&… args);
template bind(F&& f, Args&&… args);

f - Callable object (function object, pointer to function, reference to function, pointer to member function, or pointer to data member) that will be bound to some arguments
args - list of arguments to bind, with the unbound arguments replaced by the placeholders_1, _2, _3… of namespace std::placeholders

int fun(int a, int b, int c, int d)
{
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
    std::cout << d << std::endl;
    return 0;
}
void bind_test()
{
    auto f = std::bind(fun, std::placeholders::_1, std::placeholders::_2, 300, 400);
    f(100, 200);
}
int main()
{
    bind_test();
    return 0;
}

网络编程中, 经常要使用到回调函数。 当底层的网络框架有数据过来时,往往通过回调函数来通知业务层。 这样可以使网络层只专注于 数据的收发, 而不必关心业务 在c语言中, 回调函数的实现往往通过函数指针来实现。 但是在c++中 , 如果回调函数是一个类的成员函数。这时想把成员函数设置给一个回调函数指针往往是不行的 因为类的成员函数,多了一个隐含的参数this。 所以直接赋值给函数指针肯定会引起编译报错。

std::initializer_list

header

template
class initializer_list

An object of type std::initializer_list is a lightweight proxy object that provides access to an array of objects of type const T.

Implementing a constructor that takes a std::initializer_list parameter allows us to use list initialization with our custom classes. We can also use std::initializer_list to implement other functions that need to use an initializer list, such as an assignment operator.

其作用在于可以将list作为一个object,尤其是用在vector这种的构造函数上面

#include <iostream>
#include <vector>
#include <initializer_list>

template <class T>
struct S {
    std::vector<T> v;
    S(std::initializer_list<T> l) : v(l) {
         std::cout << "constructed with a " << l.size() << "-element list\n";
    }
    void append(std::initializer_list<T> l) {
        v.insert(v.end(), l.begin(), l.end());
    }
    std::pair<const T*, std::size_t> c_arr() const {
        return {&v[0], v.size()};  // copy list-initialization in return statement
                                   // this is NOT a use of std::initializer_list
    }
};

template <typename T>
void templated_fn(T) {}

int main()
{
    S<int> s = {1, 2, 3, 4, 5}; // copy list-initialization
    s.append({6, 7, 8});      // list-initialization in function call

    std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";

    for (auto n : s.v)
        std::cout << n << ' ';
    std::cout << '\n';

    std::cout << "Range-for over brace-init-list: \n";

    for (int x : {-1, -2, -3}) // the rule for auto makes this ranged-for work
        std::cout << x << ' ';
    std::cout << '\n';

    auto al = {10, 11, 12};   // special rule for auto

    std::cout << "The list bound to auto has size() = " << al.size() << '\n';

//    templated_fn({1, 2, 3}); // compiler error! "{1, 2, 3}" is not an expression,
                             // it has no type, and so T cannot be deduced
    templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
    templated_fn<std::vector<int>>({1, 2, 3});           // also OK
}
#include <cassert> // for assert()
#include <initializer_list> // for std::initializer_list
#include <iostream>

class IntArray
{
private:
    int m_length{};
    int *m_data{};

public:
    IntArray() = default;

    IntArray(int length) :
        m_length{ length },
        m_data{ new int[length]{} }
    {

    }

    IntArray(std::initializer_list<int> list) : // allow IntArray to be initialized via list initialization
        IntArray(static_cast<int>(list.size())) // use delegating constructor to set up initial array
    {
        // Now initialize our array from the list
        int count{ 0 };
        for (auto element : list)
        {
            m_data[count] = element;
            ++count;
        }
    }

    ~IntArray()
    {
        delete[] m_data;
        // we don't need to set m_data to null or m_length to 0 here, since the object will be destroyed immediately after this function anyway
    }

    IntArray(const IntArray&) = delete; // to avoid shallow copies
    IntArray& operator=(const IntArray& list) = delete; // to avoid shallow copies

    int& operator[](int index)
    {
        assert(index >= 0 && index < m_length);
        return m_data[index];
    }

    int getLength() const { return m_length; }
};

int main()
{
    IntArray array{ 5, 4, 3, 2, 1 }; // initializer list
    for (int count{ 0 }; count < array.getLength(); ++count)
        std::cout << array[count] << ' ';

    return 0;
}

std::pair

<utility>

template<class T1, class T2> struct pair;

member object
first T1
second T2

std::enable_shared_from_this

header
template class enable_shared_from_this;

std::enable_shared_from_this allows an object t that is currently managed by a std::shared_ptr named pt to safely generate additional std::shared_ptr instances pt1, pt2, ... that all share ownership of t with pt.

利用enable_shared_from_this可以对类型为std::shared_ptr的对象pt,pt这个对象管理的是t,安全的产生出其实例化pt1,pt2,…并且他们共享pt的t

std::end

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() 
{
    std::vector<int> v = { 3, 1, 4 };
    if (std::find(std::begin(v), std::end(v), 5) != std::end(v)) {
        std::cout << "found a 5 in vector v!\n";
    }

    int a[] = { 5, 10, 15 };
    if (std::find(std::begin(a), std::end(a), 5) != std::end(a)) {
        std::cout << "found a 5 in array a!\n";
    }
}

参考资料

https://www.geeksforgeeks.org/auto_ptr-unique_ptr-shared_ptr-weak_ptr-2/
https://en.cppreference.com/w/cpp/memory/enable_shared_from_this