优先使用make_unique 和 make_shared
make_unique在c++11里面没有引入,但是你可以自己写一个
template <typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args&& ...args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
使用make版本和使用new的本质不同
-
make版本不需要显示的使用new, 如果是unique就使用make_unique,如果是shared就是用make_shared;
不依赖于显式new的这种方式,在库之间依赖的时候通常减少了很多bug出现
同时减少代码的大小
- 避免异常安全
对于函数 void invoke(shared_ptr
memory, int value); 我们调用 invoke(shared_ptr
(new int()), getMemory());,这种方式存在潜在的异常安全 期待的顺序为
new int shared_ptr 得到int内存 调用getMemory()
但是编译器可能调整函数上的调用顺序
new int 调用getMemory() shared_ptr 得到int内存
如果调用getMemory出现了异常,那么 new出来的空间就内存泄漏了
修改的方式:
-
使用 make版本,他让 new和shared一体化
-
在外部使用shared_ptr,为了效率也可以使用std::move(),使用移动好处多多对吧
shared_ptr<int> test(new int()); invoke(std::move(test), getMemory());
-
效率
shared_ptr
(new int()) 如果是这样调用,造成的内存分配就是两次,一个是new,一个是内部的control block的内存分配
使用make版本代替
这样的话,make版本内部使用allocated一下子分配包含new和control block的内存大小空间,并且这样加快程序运行速度、减小内存碎片的分配
额外需要使用new的情况
- 想要自己提供额外的析构器,需要使用主动new
- 初始化列表,make版本默认内部使用()调用,无法使用{}初始化列表;但是也可以外面自己构建一个{}初始化列表,然后使用()传递进去
- 那些重载了new和delete的类,因为一般情况下类的特殊内存重载都是针对于类本身大小来做的,但是make版本的分配是类大小加上control block的内存大小空间,所以需要使用显式new
- 因为make版本是把类大小加上control block的内存大小放在一起分配的空间,那么即使内部引用计数为0,也需要等到control block被销毁才能被销毁(因为weak_ptr的问题),也就是只有当weak_count为0,control Block这片内存才会释放;这也就延长了动态分配的chunk的内存存活期
一个圆,圆内是你会的,圆外是你不知道的。而当圆越大,你知道的越多,不知道的也越多了