C++讀書筆記(牛客網)
1.constexpr變量:聲明為constexpr的變量一定是一個常量,新標准允許定義一種特殊的constexpr函數使得編譯時就可計算結果,這樣就能用constexpr函數去初始化constexpr變量。
2.類型別名:1.typedef 2.using SI = Sales_item; //SI是Sales_item的別名聲明,把等號左側的名字規定成等號右側類型的別名 3.using可以起模板別名
3.auto:auto讓編譯器通過初始值來推算變量類型。auto i = 0, *p = &i; //ok auto sz = 0, pi = 3.14; //error, 類型不統一
auto一般會忽略頂層const,保留底層const。如果希望保留頂層const,要明確指出 const auto p = ci;
設置類型為auto的引用時,初始值中的頂層const屬性保留。
底層 * 頂層: int const * const
4.decltype:類型指示符,頂層const能被保留,decltype((i)) d; //error, 對表達式套括號的結果永遠是引用,不套括號則僅當i是引用時,才是引用。
5.范圍for語句:for(declaration: expression) statement
expression是一個對象,表示一個序列;declaration部分定義一個變量,被用於訪問序列中的基礎元素,每次迭代該變量會被初始化為expression的下一個元素值。
如:
1 vector<int> v = {0, 1, 2, 3, 4, 5}; 2 for(auto &r: v) 3 r *= 2;
6.標准庫begin()和end():begin(arr)返回指向arr首元素的指針, end(arr)返回指向arr尾元素下一位置的指針。
7.列表初始化返回值:vector<string> f(){ if(true) return {}; else return {"fun", "ok"}; }
8.定義尾置返回類型:任何函數的定義都能使用尾置返回類型,但對返回類型比較復雜的函數最有效,比如返回數組的指針或數組的引用。尾置返回類型跟在形參列表后,並以->開頭,本應該出現返回類型的地方則放置auto。比如:
auto func(int i) -> int(*) [10];//返回類型為int(*)[10]
9.容器的列表初始化:vector<const char*> articles = {"a", "an", "the"};
10.容器的emplace操作:emplace_frnont, emplace, emplace_back, 這些操作構造而不是拷貝元素,c.emplace(iter, "999-9999"); //向iter指向的位置插入以"999-9999"為構造參數的元素
11.lambda:
[ capture ] ( params ) mutable exception attribute -> ret { body } |
(1) |
[ capture ] ( params ) -> ret { body } |
(2) |
[ capture ] ( params ) { body } |
(3) |
[ capture ] { body } |
(4) |
mutable 修飾符說明 lambda 表達式體內的代碼可以修改被捕獲的變量,並且可以訪問被捕獲對象的 non-const 方法。
exception 說明 lambda 表達式是否拋出異常(noexcept),以及拋出何種異常,類似於void f() throw(X, Y)。
attribute 用來聲明屬性。
[] // 不捕獲任何外部變量 [=] // 以值的形式捕獲所有外部變量 [&] // 以引用形式捕獲所有外部變量 [x, &y] // x 以傳值形式捕獲,y 以引用形式捕獲 [=, &z] // z 以引用形式捕獲,其余變量以傳值形式捕獲 [&, x] // x 以值的形式捕獲,其余變量以引用形式捕獲 另有一點需注意。對於 [=] 或 [&] 的形式,lambda 表達式可直接使用 this 指針。但對於 [] 的形式,如果要使用 this 指針,必須顯式傳入:[this]() { this->someFunc(); }();
lambda后緊接();表示直接調用函數,括號內為參數。例:
http://wenku.baidu.com/view/77cd432e647d27284b73514b.html?from=search
std::vector<int> c { 1,2,3,4,5,6,7 }; int x = 5; c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; } ), c.end()); for (auto i: c) { std::cout << i << ' '; } std::cout << endl; // the type of a closure cannot be named, but can be inferred with auto auto func1 = [](int i) { return i+4; }; std::cout << "func1: " << func1(6) << '\n'; // like all callable objects, closures can be captured in std::function // (this may incur unnecessary overhead) std::function<int(int)> func2 = [](int i) { return i+4; }; std::cout << "func2: " << func2(6) << '\n'; string result = [](const string & str) { return "Hello from " + str; }("second Lambda"); cout << "Result: " << result << endl;
lambda的捕獲列表只用於局部非static變量,lambda可以直接使用局部static變量和它所在函數之外聲明的名字。值捕獲的變量的值是在lambda創建時拷貝而不是在調用時拷貝,引用捕獲則使用引用所綁定的對象,與正常引用類似,要保證lambda調用時變量是存在的。
每個lambda的類型都是唯一的,一般只能通過decltype和模板匹配來獲得其類型。
vector<string> ve; int sz = 10; //接受一元謂詞的算法 auto it = find_if(ve.begin(), ve.end(), [sz](const string &a){return a.size() >= sz; } ); //接受二元謂詞的算法 sort(ve.begin(), ve.end(), [](const string &a, const string &b){ return a.size() < b.size();} );
12.標准庫bind函數:
參數綁定 http://blog.csdn.net/fjb2080/article/details/7527715
auto newCallable = bind(callable, arg_list);
arg_list中的參數可能包含形如_n的名字,其中n是整數,表示newCallable的參數,占據了傳遞給newCallable的參數的位置,_n表示為newCallable的第n個參數,在命名空間std::placeholeders里。
using namespace std::placeholders; //例1: bool check_size(const string &s, string::size_type sz){ return s.size() >= sz; } auto check6 = bind(check_size, _1, 6); string s = "hello"; bool b1 = check6(s);//check6(s)會調用check_size(s, 6) //例2:f是一個包含5個參數的函數 auto g = bind(f, a, b, _2, c, _1); g(X, Y);//即f(a, b, Y, c, X); //例3:ve是vector容器,cmp是一個比較函數 sort(ve.begin(), ve.end(), cmp); sort(ve.begin(), ve.end(), bind(cmp, _2, _1));//按cmp逆序排列
13.智能指針
shared_ptr允許多個指針指向同一個對象, unique_ptr則獨占所指向的對象。
智能指針是一種類模板。
默認初始化的智能指針中保存着空指針,內部有一個關聯的計數器,計數器為0時釋放自己管理的對象。
shared_ptr<string> p4 = make_shared<string>(10, '9'); //類似順序容器的emplace函數,使用動態內存
附: shard_ptr與unique_ptr的簡單實現
1 // https://www.cnblogs.com/howo/p/8468713.html 2 3 // 4 // SharedPtr.hpp 5 // SharedPtr 6 // 7 // Created by 顧浩 on 24/2/18. 8 // Copyright © 2018 顧浩. All rights reserved. 9 // 10 11 #ifndef SHARED_PTR_H 12 #define SHARED_PTR_H 13 14 #include <iostream> 15 16 using namespace std; 17 18 template<typename T> 19 class SharedPtr { 20 public: 21 SharedPtr() : _ptr((T *)0), _refCount(0) 22 { 23 } 24 25 SharedPtr(T *obj) : _ptr(obj), _refCount(new int(1)) 26 { 27 cout<<"create object : "<<*_ptr<<"\trefCount = 1"<<endl; 28 } 29 30 SharedPtr(SharedPtr &other) : _ptr(other._ptr), _refCount(&(++*other._refCount)) 31 { 32 cout<<"copy constructor : "<<*_ptr<<"\trefCount = "<<*_refCount<<endl; 33 } 34 35 ~SharedPtr() 36 { 37 if(_ptr && --*_refCount == 0) { 38 cout<<*_ptr<<"\trefCount = 0. delete the _ptr:"<<*_ptr<<endl; 39 delete _ptr; 40 delete _refCount; 41 } 42 } 43 44 SharedPtr &operator=(SharedPtr &other) 45 { 46 if(this==&other) return *this; 47 ++*other._refCount; 48 if(--*_refCount == 0) { 49 cout<<"in function operator = . delete "<<*_ptr<<endl; 50 delete _ptr; 51 delete _refCount; 52 } 53 _ptr = other._ptr; 54 _refCount = other._refCount; 55 cout<<"in function operator = . "<<*_ptr<<"\t_refCount = "<<*_refCount<<endl; 56 return *this; 57 } 58 59 T *operator->() 60 { 61 if(_refCount == 0) return 0; 62 return _ptr; 63 } 64 65 T &operator*() 66 { 67 if (_refCount == 0) return (T*)0; 68 return *_ptr; 69 } 70 71 private: 72 T *_ptr; 73 int *_refCount; //should be int*, rather than int 74 }; 75 76 #endif /* SharedPtr_h */
1 #ifndef _UNIQUE_PTR_H 2 #define __UNIQUE_H 3 class Delete { 4 public: 5 template<typename T> 6 void operator()(T *p) const { 7 delete p; 8 } 9 }; 10 template<typename T,typename D = Delete > 11 class unique_ptr { 12 public: 13 explicit unique_ptr(T *pp = nullptr ,const D &dd = D() ): 14 un_ptr(pp), del(dd) 15 { 16 } 17 18 ~unique_ptr() 19 { 20 del(un_ptr); 21 } 22 23 /* 不支持拷貝與賦值 */ 24 unique_ptr(const unique_ptr&) = delete ; 25 unique_ptr& operator=(const unique_ptr& ) = delete ; 26 27 /* 移動賦值與移動拷貝 */ 28 unique_ptr( unique_ptr&& right_value): 29 un_ptr(right_value.un_ptr),del(std::move(right_value.del)) { 30 right_value.un_ptr = nullptr ; 31 } 32 33 unique_ptr& operator=( unique_ptr&& right_value ) noexcept { 34 if(this != &right_value ){ 35 std::cout << "operator && right_value " << std::endl ; 36 del(*this); 37 un_ptr = right_value.un_ptr; 38 del = std::move(right_value.del); 39 right_value.un_ptr = nullptr ; 40 } 41 return *this ; 42 } 43 44 //u.release() u 放棄對指針的控制權,返回指針,並將 u 置為空 45 T* release(){ 46 T *tmp = un_ptr ; 47 un_ptr = nullptr ; 48 return tmp; 49 } 50 51 /* 52 u.reset() 釋放u指向的對象 53 u.reset(q) 如果提供了內置指針q,就令u指向這個對象 54 u.reset(nullptr) 將 u 置為空 55 */ 56 void reset(T* q = nullptr){ 57 del(un_ptr); 58 un_ptr = q; 59 } 60 void swap(unique_ptr &other ) noexcept { 61 std::swap(un_ptr, other.un_ptr); 62 std::swap(del, other.del) ; 63 } 64 T* get() { return un_ptr; } 65 D& get_deleter(){ return del; } 66 T& operator*() { return *un_ptr; } 67 T* operator->() { return un_ptr; } 68 private: 69 T *un_ptr = nullptr ; 70 D del ; 71 }; 72 #endif
