当前位置:  开发笔记 > 编程语言 > 正文

为什么shared_ptr使用placement new

如何解决《为什么shared_ptr使用placementnew》经验,为你挑选了2个好方法。

我在许多地方读过,当make_shared用于创建一个时shared_ptr,它的控制块包含一个足够大的存储块来容纳一个T,然后该对象是在存储内部构建的,具有新的位置.像这样的东西:

template
struct shared_ptr_control_block {
    std::atomic count;
    std::atomic weak_count;
    std::aligned_storage_t storage;
};

但我有点困惑为什么我们不能只有一个成员变量与类型T?为什么要创建原始存储然后使用新的贴图?不能与普通的类型对象一步合并T吗?



1> Martin Bonne..:

它允许终身管理.

控制块直到weak_count为零才被销毁.storage一旦count达到零,对象就会被销毁.这意味着你需要storage在计数达到零时直接调用析构函数,而不是在控制块的析构函数中.

为了防止控制块的析构函数调用析构函数storage,实际的类型storage不能T.

如果我们只有强引用计数,那么a T会很好(并且更简单).


实际上,实现比这复杂一点.请记住,一个shared_ptr可以通过分配构成Tnew,然后构建shared_ptr从.因此实际控制块看起来更像:

template
struct shared_ptr_control_block {
    std::atomic count;
    std::atomic weak_count;
    T* ptr;
};

什么make_shared分配是:

template
struct both {
    shared_ptr_control_block cb;
    std::aligned_storage_t storage;
};

cb.p设置为地址storage.分配both结构make_shared意味着我们获得单个内存分配,而不是两个(并且内存分配很昂贵).

注意:我已经简化了:必须有一种方法让shared_ptr析构函数知道控制块是否属于both(在这种情况下,内存在完成之前无法释放),或者不是(在这种情况下可以提前释放) .这可能是一个简单的bool标志(在这种情况下控制块更大),或者通过在指针中使用一些备用位(这是不可移植的 - 但标准库实现不必是可移植的).实现可能复杂,以避免在该情况下完全存储指针make_shared.



2> MikeMB..:

由于弱指针可能比存储的对象寿命长,因此控制块的寿命可能必须超过存储对象的寿命.如果托管对象是一个成员变量,它只能在控制块被销毁时被破坏(或者析构函数将被调用两次).

即使在对象本身被破坏之后存储仍然分配的事实实际上可能是make_shared存储器约束系统的缺点(尽管我不知道这是否是在实践中遇到的事情).

推荐阅读
wurtjq
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有