优先使用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的本质不同

  1. make版本不需要显示的使用new, 如果是unique就使用make_unique,如果是shared就是用make_shared;

    不依赖于显式new的这种方式,在库之间依赖的时候通常减少了很多bug出现

    同时减少代码的大小

    1. 避免异常安全

    对于函数 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出来的空间就内存泄漏

    修改的方式:

    1. 使用 make版本,他让 new和shared一体化

    2. 在外部使用shared_ptr,为了效率也可以使用std::move(),使用移动好处多多对吧

      shared_ptr<int> test(new int());
      invoke(std::move(test), getMemory());
      
    3. 效率

    shared_ptr(new int())

    如果是这样调用,造成的内存分配就是两次,一个是new,一个是内部的control block的内存分配

    使用make版本代替

    这样的话,make版本内部使用allocated一下子分配包含new和control block的内存大小空间,并且这样加快程序运行速度、减小内存碎片的分配

额外需要使用new的情况

  1. 想要自己提供额外的析构器,需要使用主动new
  2. 初始化列表,make版本默认内部使用()调用,无法使用{}初始化列表;但是也可以外面自己构建一个{}初始化列表,然后使用()传递进去
  3. 那些重载了new和delete的类,因为一般情况下类的特殊内存重载都是针对于类本身大小来做的,但是make版本的分配是类大小加上control block的内存大小空间,所以需要使用显式new
  4. 因为make版本是把类大小加上control block的内存大小放在一起分配的空间,那么即使内部引用计数为0,也需要等到control block被销毁才能被销毁(因为weak_ptr的问题),也就是只有当weak_count为0,control Block这片内存才会释放;这也就延长了动态分配的chunk的内存存活期
posted @ 2021-06-14 23:04  make_wheels  阅读(1600)  评论(0编辑  收藏  举报