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

时间:2015-12-12 18:23:24

标签: c++ c++11 shared-ptr smart-pointers make-shared

由于C ++ 11,由于几个原因,开发人员倾向于将智能指针类用于动态生命周期对象。对于那些新的智能指针类,标准,甚至建议不使用new之类的运算符,他们建议使用make_sharedmake_unique来避免一些错误。

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

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

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

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

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

auto ip = make_shared<int>(12);

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

auto ip = make_shared<int>(12, deleter);

5 个答案:

答案 0 :(得分:46)

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

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

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

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

答案 1 :(得分:11)

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

  

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

因此,您可以推断出您无法设置自定义删除。 为此,您必须通过右侧constructor为自己创建shared_ptr 作为建议列表中构造函数的示例,您可以使用:

template< class Y, class Deleter > 
shared_ptr( Y* ptr, Deleter d );

因此,代码将类似于:

auto ptr = std::shared_ptr(new MyClass{arg1, arg2}, myDeleter);

而不是:

auto ptr = std::make_shared<MyClass>(arg1, arg2);

答案 2 :(得分:4)

你不能。 make_shared<T>将提供的参数转发给类型为T的构造函数。当您需要默认删除器时,它用于简单的情况。

答案 3 :(得分:3)

未指明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);

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

答案 4 :(得分:0)

如果使用自定义删除器,则在创建智能指针对象时不能使用make_uniquemake_shared函数。由于我们需要提供自定义删除器,因此这些功能不支持该功能。

如果您需要自定义删除器或从其他地方采用原始指针,请勿使用make_unique或make_shared

这个想法是,如果您需要一种专门的方式来删除对象,那么您可能也需要一种专门的方式来创建它们。

让我们说一门测验

#include <iostream>    
using namespace std;    
class Test
{
private : 
    int data; 
    public : 
    Test() :data{0}
    {
        cout << "Test constructor (" << data << ")" << endl;
    }
    Test(int d) : data{ d }
    {
        cout << "Test constructor (" << data << ")" << endl; 
    }
    int get_data() const { return data; }
    ~Test()
    { 
        cout << "Test Destructor (" << data << ')' << endl; 
    }
};

// main function. 
int main()
{
   // It's fine if you use  make_shared and custom deleter like this
   std::shared_ptr<Test> ptr(new Test{1000},
            [](Test *ptr)
            {
                cout << "some Code that you want to execute "; 
                delete ptr;
            });
         return 0;
}

但是,如果使用make_shared函数,则会出现编译器错误

std::shared_ptr<Test> ptr = make_shared<Test>(1000,
            [](Test *ptr){
               cout << "some Code that you want to execute "; 
               delete ptr;
            });

基本上,make_shared函数是newdelete的包装器,如果要自定义删除器,则必须提供自己的newdelete