我什么时候想从原始指针构造共享指针

Mik*_*eMB 17 c++ shared-ptr c++11

感谢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,因为该对象应该被创建为首先是"共享"或"独特"的对象.

Nia*_*all 14

弹出的第一个用例是删除器不是默认值delete.

例如,在Windows环境中,必须有时使用COM对象,必须通过对象本身释放这些对象Release.当然可以使用ATL,但不是每个人都想使用它.

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());
Run Code Online (Sandbox Code Playgroud)

更常见的情况 - 但仍然有效 - 是在dll,OS或库中自定义分配对象(句柄或甚至原始内存)并且具有必须调用的自己的关联清理函数(可能会或可能不会delete依次调用) ).如果涉及内存分配std::allocate_shared,则可以在不暴露原始指针的情况下更好地控制要使用的分配器.

我个人的感觉是,std::make_sharedstd::allocate_shared,要求建立一个shared_ptr从原始指针正变得越来越少.即使是上面的情况,也可以包含在公用事业分配和管理功能中,从主业务逻辑代码中删除.

  • @Potatoswatter.是的,如果创建涉及内存分配,但我不确定它是否适用于"句柄"类型分配(等文件句柄). (2认同)

Chr*_*rew 9

Scott Meyers列出了Effective Modern C++中的几个例外

第一个已被提及.如果您需要提供自定义删除器,则无法使用make_shared.

第二个是如果你在一个有内存问题的系统上并且你正在分配一个非常大的对象,那么使用make_shared为对象和包含引用计数的控制块分配一个块.如果您有任何s指向该对象,则无法释放内存.另一方面,如果你没有使用过,那么一旦删除了最后一个,那么可以释放非常大的对象的内存.weak_ptrmake_sharedshared_ptr


utn*_*tim 5

•是否有其他合法用例?

是:资源未映射到新/删除的情况:

handle_type APIXCreateHandle(); // third party lib
void APIXDestroyHandle(handle_type h); // third party lib
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将需要直接使用构造函数.

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

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

•相同的指南(无论它们是什么)是否适用于shared_ptr :: reset(T*)?

我认为他们不应该.如果您真的想要,可以使用带有std :: make_shared调用结果的赋值替换重置调用.我更愿意看到重置调用 - 它在意图中会更明确.

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

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

相对容易说[...](我相信这是正确的建议?).但我想知道它是不是一般的设计气味

使用它不是设计气味; 只有当std :: make_shared/std :: make_unique 也能正常工作时才使用它.

编辑:解决问题的要点:您可能无法为此添加静态分析规则,除非您还向其添加约定/例外列表(即"自定义删除和第三方lib API适配除外"应始终使用layers,make_shared和make_unique").某些文件可能会跳过这样的规则.

当您直接使用构造函数时,将它们放在专用于此的函数中可能是个好主意(类似于make_unique和make_shared这样做):

namespace api_x
{
    std::shared_ptr<handle_type> make_handle(); // calls APIXCreateHandle internally
                                                // also calls the constructor
                                                // to std::shared_ptr
}
Run Code Online (Sandbox Code Playgroud)