首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >什么时候要从原始指针构造共享指针?

什么时候要从原始指针构造共享指针?
EN

Stack Overflow用户
提问于 2015-07-24 08:11:27
回答 6查看 1.7K关注 0票数 17

多亏了std::make_shared,我想知道,作为原始指针的std::shared_ptr的构造函数是否有任何值,除了与遗留/库代码进行接口时(例如在存储工厂的输出时)。

  • 还有其他合法的用例吗?
  • 避免构造函数是合理的建议吗?
  • 即使是将代码检查放到适当的位置,以警告程序员何时使用它,也是如此吗?
  • 同样的准则(不管是什么)是否适用于shared_ptr<T>::reset(T*)

关于代码检查:我知道与遗留/库代码的接口很常见,所以自动化的代码检查可能会有问题,但在大多数情况下,到目前为止,我还是宁愿使用unique_ptr,我也不是在谈论在-Wall上弹出的编译器警告,而是在代码评审期间使用静态代码分析的规则。

我的动机:

说“不要使用std::shared_ptr<T>(new T(...))__,总是喜欢std::make_shared<T>(...)__”比较容易(我认为这是正确的建议?)。但是,我想知道这是不是一般的设计味道,是否必须从原始指针创建shared_ptr,甚至--尤其是--如果对象不仅仅是通过new创建的,因为对象本来应该是作为“共享”或“唯一”对象创建的。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2015-07-24 08:23:01

想到的第一个用例是,删除器不是默认的delete

例如,在windows环境中,COM对象必须在某些时候使用,这些对象的发布必须通过Release对对象本身进行。当然,ATL是可以使用的,但并不是每个人都想使用它。

代码语言:javascript
运行
复制
struct ReleaseCom {
  template <class T>
  void operator() (T* p) const
  {
    p->Release();
  }
};
IComInterface* p = // co created or returned as a result
std::share_ptr<IComInterface> sp(p, ReleaseCom());

一个更不常见的情况--但仍然有效--是当一个对象(句柄,甚至是原始内存)在dll、OS或库中自定义分配,并且有它自己的相关清理函数,必须调用它(可能调用也可能不调用delete )。如果涉及内存分配,std::allocate_shared提供了对分配程序的更强控制,该分配程序将在不公开原始指针的情况下使用。

我个人的感觉是,给定std::make_sharedstd::allocate_shared,使用原始指针构造shared_ptr的要求越来越少。即使是上述情况,也可以包装成实用程序分配和管理功能,从主要业务逻辑代码中删除。

票数 14
EN

Stack Overflow用户

发布于 2015-07-24 08:40:03

Scott列出了有效的现代C++中的几个例外

第一个问题已被提及。如果需要提供自定义删除器,则不能使用make_shared

第二种情况是,如果您所处的系统存在内存问题,并且您正在分配一个非常大的对象,那么使用make_shared为对象和包含弱引用计数的控制块分配一个块。如果您有指向对象的任何weak_ptr,则无法释放内存。另一方面,如果您没有使用make_shared,那么一旦删除了最后一个shared_ptr,就可以释放这个非常大的对象的内存。

票数 9
EN

Stack Overflow用户

发布于 2015-07-24 08:29:59

·还有其他合法的用例吗?

是的:在资源没有映射到新/删除的情况下:

代码语言:javascript
运行
复制
handle_type APIXCreateHandle(); // third party lib
void APIXDestroyHandle(handle_type h); // third party lib

在这种情况下,您将希望直接使用构造函数。

·避免使用构造函数是否合理?

当功能与make_shared重叠时,是的。

·同样的准则(不管是什么)是否适用于shared_ptr::reset(T*)?

如果你真的想要的话,你可以用一个std::make_shared调用的结果来代替重置调用。我宁愿看到重置调用,而不是-它的意图将更加明确。

关于代码检查:我知道与遗留/库代码的接口非常常见。

考虑将第三方库包装到一个接口中,以确保返回的值是唯一的_ptr-包装的。这将为您提供集中化点和其他方便/安全优化的机会。

..。相对容易。但我不知道这是不是一般的设计味

使用它不是设计气味;只有当std::make_/:make_unique同样工作时才使用它。

编辑:为了解决问题的要点:您可能无法为此添加静态分析规则,除非您还向其添加了约定/异常列表(即“除了自定义删除层和第三方lib适配层之外,make_shared和make_unique应该始终被使用”)。对于您的一些文件,可能会跳过这样的规则。

但是,当您确实直接使用构造函数时,最好将它们放在专用于此的函数中(类似于make_unique和make_shared所做的):

代码语言:javascript
运行
复制
namespace api_x
{
    std::shared_ptr<handle_type> make_handle(); // calls APIXCreateHandle internally
                                                // also calls the constructor
                                                // to std::shared_ptr
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31605357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档