完美轉發及其實現
- 函數模版可以將自己的參數完美地轉發給內部調用的其他函數。所謂完美,即不僅能準確地轉發參數的值,還能保證被轉發參數的左右值屬性不變
- 引用折疊:如果任一引用為左值引用,則結果為左值引用,否則為右值引用。
& && -> &
&& & -> &
& & -> &
&& && -> &&
void actualRun(int a) {}
template <typename T>
void testPerfectForward(T &¶m) {actualRun(param);
}void testPerfectForwardMain() {int a = 0;testPerfectForward(a);
}
上述 T 為int &。 那么整個為 int & &&-> int &
回到完美轉發,假設現在我需要轉發a,那么注意一下實現完美轉發需要這樣寫
template <typename T>
void testPerfectForward1(T &¶m) {actualRun(std::forward(param));
}
forward大致實現原理
static_cast + &&
template <typename T>
T&& forwad(T ¶m) {return static_cast<T&&>(param);
}
注意其實std::move底層實現也是 static_cast
C++11 nullptr:初始化空指針
- #define NULL 0
#include <iostream>
using namespace std;void isnull(void *c){cout << "void*c" << endl;
}
void isnull(int n){cout << "int n" << endl;
}
void testNull1() {isnull(0);//isnull(NULL);//Call to 'isnull' is ambiguousisnull((void*)NULL);/*int nvoid*c*/
}
1 . nullptr 是 nullptr_t 類型的右值常量,專用于初始化空類型指針。nullptr_t 是 C++11 新增加的數據類型,可稱為“指針空值類型”。也就是說,nullpter 僅是該類型的一個實例對象(已經定義好,可以直接使用),如果需要我們完全定義出多個同 nullptr 完全一樣的實例對象。
- nullptr 可以被隱式轉換成任意的指針類型。故如下:
void testNull2() {isnull(0);//isnull(NULL);//Call to 'isnull' is ambiguousisnull((void*)NULL);isnull(nullptr);/*int nvoid*cvoid*c*/}
- 借助執行結果不難看出,由于 nullptr 無法隱式轉換為整形,而可以隱式匹配指針類型,因此執行結果和我們的預期相符
void testNullMain() {
// int *p = 0;
// int *q = NULL;
// testNull1(0);
// testNull1(NULL);
}
.C++11 shared_ptr智能指針
void deleteInt(int *p) {delete []p;
}
void testSharedPtr () {std::cout << "testSharePtr: " << endl;//初始化空的shareptr,引用計數為0不是1std::shared_ptr<int> p1;std::shared_ptr<int> p2(nullptr);std::shared_ptr<int> p3(new int(10));std::shared_ptr<int> p4 = std::make_shared<int>(10);//調用拷貝構造函數std::shared_ptr<int> p5(p4); //或者 p4 = p3;//調用移動構造函數std::shared_ptr<int> p6(std::move(p4)); //或者p6 = std::move(p4)//智能指針可以拷貝,給多個智能指針用,引用計數+1,但是普通指針,只能拷貝給一個智能指針int *p = new int(1);std::shared_ptr<int> pp1(p);
// std::shared_ptr<int> pp2(p); //錯誤!!!!// 在初始化 shared_ptr 智能指針時,還可以自定義所指堆內存的釋放規則,這樣當堆內存的引用計數為 0 時,會優先調用我們自定義的釋放規則。在某些場景中,自定義釋放規則是很有必要的,比如,對于申請的動態數組來說,share—_ptr指針默認的釋放規則是不支持釋放數組的,值呢個自定義對于的釋放規則,如下://釋放規則可以使用 C++11 標準中提供的 default_delete<T> 模板類,我們也可以自定義釋放規則:std::shared_ptr<int> p10(new int[10], std::default_delete<int[]>());std::shared_ptr<int> p11(new int[10], deleteInt);std::shared_ptr<int> p12(new int[10], [](int *p){delete []p;});std::shared_ptr<int> ppp1 = std::make_shared<int>(10);std::shared_ptr<int> ppp2(ppp1);std::cout << *ppp2 << endl;cout<< ppp2.use_count()<<endl;ppp1.reset();if (p1) {std::cout << "ppp1 is not null !"<< endl;} else {std::cout << "ppp1 is null !"<< endl;}std::cout << *ppp2 << endl;cout<< ppp2.use_count()<<endl;
}
表 1 shared_ptr<T>模板類常用成員方法成員方法名 功 能operator=() 重載賦值號,使得同一類型的 shared_ptr 智能指針可以相互賦值。operator*() 重載 * 號,獲取當前 shared_ptr 智能指針對象指向的數據。operator->() 重載 -> 號,當智能指針指向的數據類型為自定義的結構體時,通過 -> 運算符可以獲取其內部的指定成員。swap() 交換 2 個相同類型 shared_ptr 智能指針的內容。reset() 當函數沒有實參時,該函數會使當前 shared_ptr 所指堆內存的引用計數減 1,同時將當前對象重置為一個空指針;當為函數傳遞一個新申請的堆內存時,則調用該函數的 shared_ptr 對象會獲得該存儲空間的所有權,并且引用計數的初始值為 1。get() 獲得 shared_ptr 對象內部包含的普通指針。use_count() 返回同當前 shared_ptr 對象(包括它)指向相同的所有 shared_ptr 對象的數量。unique() 判斷當前 shared_ptr 對象指向的堆內存,是否不再有其它 shared_ptr 對象再指向它。operator bool() 判斷當前 shared_ptr 對象是否為空智能指針,如果是空指針,返回 false;反之,返回 true。*/
C++11 unique_ptr智能指針
unique_ptr 指針指向的堆內存無法同其它 unique_ptr 共享,也就是說,每個 unique_ptr 指針都獨自擁有對其所指堆內存空間的所有權
void testUniqueptr() {std::unique_ptr<int> p1(new int(3));
// std::unique_ptr<int> p1(p2);std::unique_ptr<int> p2(std::move(p1));// 默認情況下,unique_ptr 指針采用 std::default_delete<T> 方法釋放堆內存。當然,我們也可以自定義符合實際場景的釋放規則。值得一提的是,和 shared_ptr 指針不同,為 unique_ptr 自定義釋放規則,只能采用函數對象的方式。例如:struct myDel {void operator()(int *p) {delete p;}};std::unique_ptr<int, myDel> p7(new int);
// std::unique_ptr<int, myDel> p6(new int);std::unique_ptr<int> p10(new int);*p10 = 10;//p10釋放當前所指堆的所有權, 但該存儲空間不會被銷毀,轉移給了pint *p = p10.release();std::unique_ptr<int> p11;//中 p 表示一個普通指針,如果 p 為 nullptr,則當前 unique_ptr 也變成空指針;反之,則該函數會釋放當前 unique_ptr 指針指向的堆內存(如果有),然后獲取 p 所指堆內存的所有權(p 為 nullptr)。p11.reset(p);// int *p2 = p;
}
C++11 weak_ptr智能指針
weak_ptr是為了配合shared_ptr而引入的一種智能指針,它不具有普通指針的行為,沒有重載*和->兩個操作符,它的最大作用在于協助shared_ptr工作,像旁觀者那樣觀測資源的使用情況。
weak_ptr可以從一個shared_ptr或者另一個weak_ptr對象構造,獲得資源的觀測權。但weak_ptr沒有共享資源,它的構造不會引起指針引用計數的增加。
使用weak_ptr的成員函數use_count()可以觀測資源的引用計數,另一個成員函數expired()的功能等價于use_count()==0,但更快,表示被觀測的資源 (也就是shared_ptr的管理的資源)已經不復存在。
weak_ptr可以使用一個非常重要的成員函數lock()從被觀測的shared_ptr 獲得一個可用的shared_ptr對象,從而操作資源。但當expired()==true的時候,lock()函數將返回一個存儲空指針的shared_ptr。
shared_from_this
#include<memory>class Test: public std::enable_shared_from_this<Test>
{public: Test();~Test();std::shared_ptr<Test> getSharedFromThis(){return shared_from_this();}
}
在什么情況下要使類A繼承enable_share_from_this?
使用場合:當類A被share_ptr管理,且在類A的成員函數里需要把當前類對象作為參數傳給其他函數時,就需要傳遞一個指向自身的share_ptr。
我們就使類A繼承enable_share_from_this,然后通過其成員函數share_from_this()返回當指向自身的share_ptr。
以上有2個疑惑:
1.把當前類對象作為參數傳給其他函數時,為什么要傳遞share_ptr呢?直接傳遞this指針不可以嗎?
一個裸指針傳遞給調用者,誰也不知道調用者會干什么?假如調用者delete了該對象,而share_tr此時還指向該對象。
2.這樣傳遞share_ptr可以嗎?share_ptr
這樣會造成2個非共享的share_ptr指向一個對象,最后造成2次析構該對象。
————————————————
引用鏈接:https://blog.csdn.net/zk3326312/article/details/79108690
http://c.biancheng.net/view/3730.html