網站上傳照片失敗東莞seo外包公司哪家好
shared_ptr
shared_ptr繼承自__shared_ptr,其中有兩個對象,一個是指向資源的指針,一個是控制塊,指向一個引用計數對象。控制塊中存儲了強引用和弱引用的計數,強引用Uses代表shared_ptr對象的引用計數,弱引用Weaks代表weak_ptr對象的引用計數。
大概結構如上圖所示,控制塊其中也存儲了指向資源的指針。
因此在構造一個shared_ptr對象的時候,會有兩次堆分配,一次是為資源分配,一次是為控制塊分配。因為每一個指向這份資源的指針對象都需要看到同一份引用計數,因此跟資源一樣也是堆分配的。多次的堆分配和釋放也就代表效率上的損失,而且極易產生內存碎片。
make_shared
C++11同時提供了make_shared函數,這是通過構造一個shared_ptr對象,而這個對象會事先申請一塊足夠大的內存空間,用于存放管理的資源以及控制塊。即分配的堆空間是連續(xù)的,因此只有一次堆內存分配。
內存的結構就從左邊的構造shared_ptr對象到右邊的重構對象資源指針和引用計數。
相比shared_ptr構造,減少一次內存分配,提高效率,并且內存空間連續(xù),減少內存碎片產生。但是,make_shared也存在缺點。
make_shared的缺點
自定義deleter
make_shared在構造智能指針對象的時候不能自定義deleter。在創(chuàng)建對象時同時創(chuàng)建控制塊,這個控制塊內部包含了引用計數、deleter等與管理資源相關的信息。因為資源和控制塊是屬于同一塊申請的內存,所以使用自定義deleter可能會導致控制塊內存被不正確地釋放。因此,如果要使用deleter,應該使用shared_ptr直接構造。
構造函數
因為make_shared需要用到類的拷貝構造,因此需要被管理的類的構造函數是public的。
內存延遲歸還
因為分配的空間是連續(xù)的,在資源指針的Uses變?yōu)?之后,控制塊伴隨資源的資源不會被立即釋放,要等Weak也變?yōu)?,整塊內存才被釋放。資源只是被clear,但是但是沒有歸還操作系統(tǒng)。而如果是默認的控制塊,在資源指針的Uses變?yōu)?之后,資源會被立即釋放,內存立即歸還。
通過調試看直接構造和make_shared的區(qū)別
void test2()
{std::shared_ptr<string> p1 = std::make_shared<std::string>(10, '9');{std::weak_ptr<std::string> wptr1;wptr1 = p1;std::shared_ptr<string> p2 = std::make_shared<std::string>("Hello");wptr1 = p2;p2 = p1;}std::cout << "end";
}void test1()
{std::shared_ptr<string> p1 = std::shared_ptr<std::string>(new std::string(10, '9'));{std::weak_ptr<std::string> wptr1;wptr1 = p1;std::shared_ptr<string> p2 = std::shared_ptr<std::string>(new std::string("Hello"));wptr1 = p2;p2 = p1;}std::cout << "end";
}int main()
{test1();test2();return 0;
}
直接構造
當wptr指向p1的時候,可以看到p1的Weaks變?yōu)榱?,weak_ptr觀察到的內容與p1一致。并且注意此時control block的value顯示為default,表示默認的控制塊。
當weak_ptr指向p2,并且將p2指向p1,意思就是p2原來管理的Hello資源要釋放掉,然后用p1拷貝構造一個對象,賦值給p2,讓p1和p2同時管理10個9。
此時可以看到weak_ptr的資源指針已經顯示Error reading,說明資源已經釋放,內存已經歸還了。
make_shared構造
此時可以看到原來為default的control block已經改為了make_shared。
重復之前的操作,把p2指向p1,再看weak_ptr的成員??梢钥吹絧tr指向的資源并沒有被釋放,只是內容并清空而已。只有當weak_ptr的生命周期結束,整個內存塊才會被釋放,歸還給操作系統(tǒng)。
這就是make_shared最主要的缺點,在某些內存要求高的場景下可能不太適用。