天津網(wǎng)站建設(shè)公騰訊廣告推廣平臺(tái)
一? ?make_shared?
1.1? make_shared 是什么?
? ? ? c++ 11 中 引入了智能指針 shared_ptr,以及一個(gè)模板函數(shù) make_shared 來生成一個(gè)制定類型的 shared_ptr。
1.2??引入 make_shared ,解決了什么問題?
? ?make_shared的引入,主要有兩點(diǎn)的提升:性能 與 異常安全
C++11 make_shared - 簡(jiǎn)書 (jianshu.com)
- ? 性能
? ? ? ? 有如下兩種方式生成? shared_ptr
int main()
{// 1.shared_ptr<string> p1(new string("66888"));cout << *p1 << endl;// 2.shared_ptr<string> p2 = make_shared<string>("888888");cout << *p2 << endl;return 0;
}
? ? ? ? ? ? ? 使用 make_shared 性能要更好一些
? shared_ptr<string> p1(new string("66888"));? 會(huì)分配兩次內(nèi)存:?
每個(gè)std::shared_ptr都指向一個(gè)控制塊,控制塊包含被指向?qū)ο蟮囊糜?jì)數(shù)以及其他東西。這個(gè)控制塊的內(nèi)存是在std::shared_ptr的構(gòu)造函數(shù)中分配的。因此直接使用new,需要一塊內(nèi)存分配給string,還要一塊內(nèi)存分配給控制塊。
? 使用???shared_ptr<string> p2 = make_shared<string>("888888");? 分配一次內(nèi)存,
? 一次分配就足夠了。這是因?yàn)閟td::make_shared申請(qǐng)一個(gè)單獨(dú)的內(nèi)存塊來同時(shí)存放 string 對(duì)象和控制塊。
- ? 異常安全
// d.h
#include<iostream>class D
{
public:D(){std::cout << "constructor D " << std::endl;}~D(){std::cout << "destructor D " << std::endl;}};// main.cppint getVal()
{throw 888;return 66;
}void init(shared_ptr<D> ptr, int val)
{}int main()
{// 1. init(std::shared_ptr<D>(new D), getVal());// 2.init(std::make_shared<D>(), getVal());return 0;
}
? 第 1 種的調(diào)用方式分為三步:
? 1.? new D
? 2. 調(diào)用 shared_ptr 類的構(gòu)造函數(shù)
? 3. 調(diào)用 getVal 函數(shù)??
????????針對(duì)不同的編譯器,上述三步的執(zhí)行順序可能不同,若是 其中的第 2 步 與第 3 步發(fā)生了調(diào)換,那么在執(zhí)行 getVal 拋出異常后,就不會(huì)再執(zhí)行 第 2 步,沒有調(diào)用 shared_ptr 的構(gòu)造函數(shù),那么就無法用 shared_ptr 來管理 第 1 步分配出的內(nèi)存。
? 第 2 種方式,用 make_shared 就不會(huì)出現(xiàn)該問題,其分為兩步
? ?1. make_shared 生成 shared_ptr 指針
? ?2.調(diào)用? getVal 函數(shù)??
上面的 1 步?與 2 步,即便發(fā)生順序調(diào)換,也不會(huì)出現(xiàn)內(nèi)存無法管理的情況
1.3? ?make_shared 源碼解析
template<typename _Tp, typename... _Args>inline shared_ptr<_Tp>make_shared(_Args&&... __args){typedef typename std::remove_const<_Tp>::type _Tp_nc; // 去除 _Tp 的 const 特性,獲取到其類本身return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),std::forward<_Args>(__args)...);// std::allocator會(huì)給我們分配一塊_Tp_nc實(shí)例需要的內(nèi)存空間// 完美轉(zhuǎn)發(fā)(perfect forward)剩余構(gòu)造函數(shù)的參數(shù)}template<typename _Tp, typename _Alloc, typename... _Args>inline shared_ptr<_Tp>allocate_shared(const _Alloc& __a, _Args&&... __args){return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,std::forward<_Args>(__args)...); // 調(diào)用 shared_ptr 的 private 構(gòu)造函數(shù)}?
make_shared 的參數(shù)是萬能引用 && ,因此參數(shù)既可以接受左值也可以接受右值。
allocate_shared 是 shared_ptr 類的 friend 函數(shù),因此可以調(diào)用 shared_ptr 的 private 構(gòu)造函數(shù)。
總之,下面的 private 構(gòu)造函數(shù)將實(shí)例內(nèi)存與計(jì)數(shù)器模塊的內(nèi)存綁定在了一起。
template<typename _Alloc, typename... _Args>__shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)
詳細(xì)解析見:從零開始寫一個(gè)shared_ptr-make_shared源代碼解析 - 知乎 (zhihu.com)
1.4? make_shared 使用例子
// person.h
class Person
{
public:Person(std::string name);Person(const Person& p);~Person();std::string& getName();void setName(std::string& name);private:std::string m_name;
};// person.cpp
#include "person.h"
#include<iostream>
Person::Person(std::string name):m_name(name)
{std::cout << "Person constructor name: " << m_name << std::endl;
}Person::Person(const Person& p)
{this->m_name = p.m_name;std::cout << "Person copy constructor name: " << this->m_name << std::endl;
}Person::~Person()
{std::cout << "Person destructor name: " << m_name << std::endl;
}std::string& Person::getName()
{return m_name;
}void Person::setName(std::string& name)
{this->m_name = name;
}// main.cpp
void testSharedPtr2()
{// 1.shared_ptr<Person> ptr(new Person("Tom"));cout << ptr->getName() << endl;// 2.shared_ptr<Person> ptr2 = make_shared<Person>("Jerry");cout << ptr2->getName() << endl;}int main()
{testSharedPtr2();return 0;
}
二? ?make_unique?
2.1? make_unique?是什么?
? ? ? ??make_unique 是 c++14 加入標(biāo)準(zhǔn)庫(kù)的,用于生成獨(dú)占型指針 std::unique_ptr?
2.2??make_unique? 解決了什么問題?
? ? ?用 make_unique 生成獨(dú)占型指針代碼量更少,符合現(xiàn)代 c++ 盡量避免使用 new? 來構(gòu)造的原則
2.3??make_unique? 簡(jiǎn)單版實(shí)現(xiàn)
template<typename T, typename... Arg> // 可能有多個(gè)參數(shù),所以用 ...
unique_ptr<T>
my_make_unique(Arg&& ... s) // 支持左值與右值,所以要用萬能引用
{return unique_ptr<T>(new T(std::forward<Arg>(s)...));
}int main()
{unique_ptr<string> ptr = my_make_unique<string>("abcdd");cout << *ptr << endl;return 0;
}
2.4??make_unique? 使用例子
很簡(jiǎn)單
int main()
{std::unique_ptr<std::string> a = std::make_unique("6666");return 0;
}
參考:C++11 make_shared - 簡(jiǎn)書 (jianshu.com)
從零開始寫一個(gè)shared_ptr-make_shared源代碼解析 - 知乎 (zhihu.com)
?《Effective Modern C++》學(xué)習(xí)筆記之條款二十一:優(yōu)先選用std::make_unique和std::make_shared,而非直接new - 知乎 (zhihu.com)