Sequence Containers
Implement data structures which can be accessed in a sequential manner
std::vector
template < class T, class Alloc = allocator
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::vector std::vector foo.swap(bar); |
clear | Clear content |
// inserting into a vector
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (3,100);
std::vector<int>::iterator it;
it = myvector.begin();
it = myvector.insert ( it , 200 );
myvector.insert (it,2,300);
// "it" no longer valid, get a new one:
it = myvector.begin();
std::vector<int> anothervector (2,400);
myvector.insert (it+2,anothervector.begin(),anothervector.end());
int myarray [] = { 501,502,503 };
myvector.insert (myvector.begin(), myarray, myarray+3);
std::cout << "myvector contains:";
for (it=myvector.begin(); it<myvector.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//myvector contains: 501 502 503 300 300 400 400 200 100 100 100
Container Adaptors
Provide a different interface for sequential containers
std::queue
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 | template |
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
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
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::map 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 writestring 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
class Alloc = allocator
> 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
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
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
template
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
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
std::enable_shared_from_this
allows an objectt
that is currently managed by a std::shared_ptr namedpt
to safely generate additional std::shared_ptr instancespt1, pt2, ...
that all share ownership oft
withpt
.
利用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