完美轉(zhuǎn)發(fā)及其實現(xiàn)
- 函數(shù)模版可以將自己的參數(shù)完美地轉(zhuǎn)發(fā)給內(nèi)部調(diào)用的其他函數(shù)。所謂完美,即不僅能準確地轉(zhuǎn)發(fā)參數(shù)的值,還能保證被轉(zhuǎn)發(fā)參數(shù)的左右值屬性不變
- 引用折疊:如果任一引用為左值引用,則結(jié)果為左值引用,否則為右值引用。
& && -> &
&& & -> &
& & -> &
&& && -> &&
void actualRun(int a) {
}
template <typename T>
void testPerfectForward(T &¶m) {
actualRun(param);
}
void testPerfectForwardMain() {
int a = 0;
testPerfectForward(a);
}
上述 T 為int &。 那么整個為 int & &&-> int &
回到完美轉(zhuǎn)發(fā),假設現(xiàn)在我需要轉(zhuǎn)發(fā)a,那么注意一下實現(xiàn)完美轉(zhuǎn)發(fā)需要這樣寫
template <typename T>
void testPerfectForward1(T &¶m) {
actualRun(std::forward(param));
}
forward大致實現(xiàn)原理
static_cast + &&
template <typename T>
T&& forwad(T ¶m) {
return static_cast<T&&>(param);
}
注意其實std::move底層實現(xiàn)也是 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 ambiguous
isnull((void*)NULL);
/*
int n
void*c
*/
}
1 . nullptr 是 nullptr_t 類型的右值常量,專用于初始化空類型指針。nullptr_t 是 C++11 新增加的數(shù)據(jù)類型,可稱為“指針空值類型”。也就是說,nullpter 僅是該類型的一個實例對象(已經(jīng)定義好,可以直接使用),如果需要我們完全定義出多個同 nullptr 完全一樣的實例對象。
- nullptr 可以被隱式轉(zhuǎn)換成任意的指針類型。故如下:
void testNull2() {
isnull(0);
//isnull(NULL);//Call to 'isnull' is ambiguous
isnull((void*)NULL);
isnull(nullptr);
/*
int n
void*c
void*c
*/
}
- 借助執(zhí)行結(jié)果不難看出,由于 nullptr 無法隱式轉(zhuǎn)換為整形,而可以隱式匹配指針類型,因此執(zhí)行結(jié)果和我們的預期相符
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,引用計數(shù)為0不是1
std::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);
//調(diào)用拷貝構(gòu)造函數(shù)
std::shared_ptr<int> p5(p4); //或者 p4 = p3;
//調(diào)用移動構(gòu)造函數(shù)
std::shared_ptr<int> p6(std::move(p4)); //或者p6 = std::move(p4)
//智能指針可以拷貝,給多個智能指針用,引用計數(shù)+1,但是普通指針,只能拷貝給一個智能指針
int *p = new int(1);
std::shared_ptr<int> pp1(p);
// std::shared_ptr<int> pp2(p); //錯誤!?。?!
// 在初始化 shared_ptr 智能指針時,還可以自定義所指堆內(nèi)存的釋放規(guī)則,這樣當堆內(nèi)存的引用計數(shù)為 0 時,會優(yōu)先調(diào)用我們自定義的釋放規(guī)則。在某些場景中,自定義釋放規(guī)則是很有必要的,比如,對于申請的動態(tài)數(shù)組來說,share—_ptr指針默認的釋放規(guī)則是不支持釋放數(shù)組的,值呢個自定義對于的釋放規(guī)則,如下:
//釋放規(guī)則可以使用 C++11 標準中提供的 default_delete<T> 模板類,我們也可以自定義釋放規(guī)則:
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 智能指針對象指向的數(shù)據(jù)。
operator->() 重載 -> 號,當智能指針指向的數(shù)據(jù)類型為自定義的結(jié)構(gòu)體時,通過 -> 運算符可以獲取其內(nèi)部的指定成員。
swap() 交換 2 個相同類型 shared_ptr 智能指針的內(nèi)容。
reset() 當函數(shù)沒有實參時,該函數(shù)會使當前 shared_ptr 所指堆內(nèi)存的引用計數(shù)減 1,同時將當前對象重置為一個空指針;當為函數(shù)傳遞一個新申請的堆內(nèi)存時,則調(diào)用該函數(shù)的 shared_ptr 對象會獲得該存儲空間的所有權(quán),并且引用計數(shù)的初始值為 1。
get() 獲得 shared_ptr 對象內(nèi)部包含的普通指針。
use_count() 返回同當前 shared_ptr 對象(包括它)指向相同的所有 shared_ptr 對象的數(shù)量。
unique() 判斷當前 shared_ptr 對象指向的堆內(nèi)存,是否不再有其它 shared_ptr 對象再指向它。
operator bool() 判斷當前 shared_ptr 對象是否為空智能指針,如果是空指針,返回 false;反之,返回 true。
*/
C++11 unique_ptr智能指針
unique_ptr 指針指向的堆內(nèi)存無法同其它 unique_ptr 共享,也就是說,每個 unique_ptr 指針都獨自擁有對其所指堆內(nèi)存空間的所有權(quán)
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> 方法釋放堆內(nèi)存。當然,我們也可以自定義符合實際場景的釋放規(guī)則。值得一提的是,和 shared_ptr 指針不同,為 unique_ptr 自定義釋放規(guī)則,只能采用函數(shù)對象的方式。例如:
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釋放當前所指堆的所有權(quán), 但該存儲空間不會被銷毀,轉(zhuǎn)移給了p
int *p = p10.release();
std::unique_ptr<int> p11;
//中 p 表示一個普通指針,如果 p 為 nullptr,則當前 unique_ptr 也變成空指針;反之,則該函數(shù)會釋放當前 unique_ptr 指針指向的堆內(nèi)存(如果有),然后獲取 p 所指堆內(nèi)存的所有權(quán)(p 為 nullptr)。
p11.reset(p);
// int *p2 = p;
}
C++11 weak_ptr智能指針
weak_ptr是為了配合shared_ptr而引入的一種智能指針,它不具有普通指針的行為,沒有重載*和->兩個操作符,它的最大作用在于協(xié)助shared_ptr工作,像旁觀者那樣觀測資源的使用情況。
weak_ptr可以從一個shared_ptr或者另一個weak_ptr對象構(gòu)造,獲得資源的觀測權(quán)。但weak_ptr沒有共享資源,它的構(gòu)造不會引起指針引用計數(shù)的增加。
使用weak_ptr的成員函數(shù)use_count()可以觀測資源的引用計數(shù),另一個成員函數(shù)expired()的功能等價于use_count()==0,但更快,表示被觀測的資源 (也就是shared_ptr的管理的資源)已經(jīng)不復存在。
weak_ptr可以使用一個非常重要的成員函數(shù)lock()從被觀測的shared_ptr 獲得一個可用的shared_ptr對象,從而操作資源。但當expired()==true的時候,lock()函數(shù)將返回一個存儲空指針的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的成員函數(shù)里需要把當前類對象作為參數(shù)傳給其他函數(shù)時,就需要傳遞一個指向自身的share_ptr。
我們就使類A繼承enable_share_from_this,然后通過其成員函數(shù)share_from_this()返回當指向自身的share_ptr。
以上有2個疑惑:
1.把當前類對象作為參數(shù)傳給其他函數(shù)時,為什么要傳遞share_ptr呢?直接傳遞this指針不可以嗎?
一個裸指針傳遞給調(diào)用者,誰也不知道調(diào)用者會干什么?假如調(diào)用者delete了該對象,而share_tr此時還指向該對象。
2.這樣傳遞share_ptr可以嗎?share_ptr 文章來源:http://www.zghlxwxcb.cn/news/detail-658194.html
這樣會造成2個非共享的share_ptr指向一個對象,最后造成2次析構(gòu)該對象。
————————————————
引用鏈接:https://blog.csdn.net/zk3326312/article/details/79108690
http://c.biancheng.net/view/3730.html文章來源地址http://www.zghlxwxcb.cn/news/detail-658194.html
到了這里,關(guān)于面試之快速學習C++11-完美轉(zhuǎn)發(fā),nullptr, shared_ptr,unique_ptr,weak_ptr,shared_from_this的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!