如何将删除函数传递给make_shared?

cav*_*gru 39 c++ smart-pointers shared-ptr make-shared c++11

从C++ 11开始,由于几个原因,开发人员倾向于将智能指针类用于动态生命周期对象.而对于那些新的智能指针类,标准,甚至建议不使用运营商,new而是建议使用make_sharedmake_unique避免一些容易出错.

如果我们喜欢使用智能指针类shared_ptr,我们可以构建一个类似的,

shared_ptr<int> p(new int(12));
Run Code Online (Sandbox Code Playgroud)

我们还希望将自定义删除器传递给智能指针类,

shared_ptr<int> p(new int(12), deleter);
Run Code Online (Sandbox Code Playgroud)

另一方面,如果我们喜欢使用make_shared分配,例如.int,而不是使用newshared_ptr构造函数,就像上面的第一个表达式,我们可以使用

auto ip = make_shared<int>(12);
Run Code Online (Sandbox Code Playgroud)

但是,如果我们也希望将自定义删除器传递给make_shared,那么有没有正确的方法呢?好像编译器,至少gcc,给出错误,

auto ip = make_shared<int>(12, deleter);
Run Code Online (Sandbox Code Playgroud)

Nic*_*las 52

正如其他人所说,make_shared不能与自定义删除器一起使用.但我想解释原因.

存在自定义删除器是因为您以某种特殊方式分配了指针,因此您需要能够以相应的特殊方式释放它.好吧,make_shared分配指针new.分配的对象new应该被释放delete.标准删除者尽职尽责.

简而言之,如果您可以使用默认的分配行为,那么您也可以使用默认的释放行为.如果您不能使用默认分配行为,则应使用allocate_shared,它使用提供的分配器来分配和取消分配存储.

此外,make_shared允许(并且几乎肯定会)T在同一分配中为shared_ptr 分配内存和控制块.这是你的删除者无法真正了解或处理的事情.鉴于allocate_shared您提供的分配器可以执行分配和解除分配任务,因此能够处理它.

  • Upvoted,我从未想过这一点,但它完全有道理.好提示. (2认同)
  • 最重要的是,因为make/allocate_shared不允许您更改"获取资源"步骤,所以它们支持自定义方式"释放资源"也没有意义.它们用于简单的创建/销毁`shared_ptr`的对象使用. (2认同)

sky*_*ack 11

文档中,make_shared接受一个参数列表,用于构造T的实例.
此外,文件说:

此函数通常用于从调用new返回的原始指针替换共享指针的构造std :: shared_ptr(new T(args ...)).

因此,您可以推断出无法设置自定义删除器.
要做到这一点,你必须shared_ptr通过正确的构造函数为自己创建.
作为建议列表中构造函数的示例,您可以使用:

template< class Y, class Deleter > 
shared_ptr( Y* ptr, Deleter d );
Run Code Online (Sandbox Code Playgroud)

因此,代码将是这样的:

auto ptr = std::shared_ptr(new MyClass{arg1, arg2}, myDeleter);
Run Code Online (Sandbox Code Playgroud)

代替:

auto ptr = std::make_shared<MyClass>(arg1, arg2);
Run Code Online (Sandbox Code Playgroud)


Jon*_*ely 6

未指定如何make_shared获取对象的内存(它可以使用operator newmalloc或某种分配器),因此自定义删除器无法知道如何做正确的事情。make_shared创建对象,因此您还必须依赖它来正确销毁对象并进行适当的清理,无论是什么。

我们还想将自定义删除器传递给智能指针类,

shared_ptr<int> p(new int(12), deleter);

我认为这不是一个非常现实的例子。当以某种特殊方式获取资源时,通常会使用自定义删除器。如果您只是new像这样创建了它,那么为什么还需要自定义删除器呢?

如果您只想在销毁时运行一些代码,请将其放入析构函数中!这样你仍然可以使用它,make_shared例如

struct RunSomethingOnDestruction {
  RunSomethingOnDestruction(int n) : i(n) { }
  ~RunSomethingOnDestruction() { /* something */ }
  int i;
};

auto px = std::make_shared<RunSomethingOnDestruction>(12);
std:shared_ptr<int> p(px, px->i);
Run Code Online (Sandbox Code Playgroud)

这为您提供了一个shared_ptr<int>make_shared(因此您可以通过 完成内存优化make_shared)创建的 ,它将在销毁时运行一些自定义代码。