45

自 C++11 以来,由于多种原因,开发人员倾向于将智能指针类用于动态生命周期对象。并且对于那些新的智能指针类,标准,甚至建议不要使用new他们建议使用make_sharedmake_unique避免一些容易出错的运算符。

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

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

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

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

另一方面,如果我们喜欢使用make_shared来分配,例如。int, 而不是 usenewshared_ptrconstructor ,就像上面的第一个表达式一样,我们可以使用

auto ip = make_shared<int>(12);

但是,如果我们还想将自定义删除器传递make_shared给 怎么办,是否有正确的方法来做到这一点?似乎编译器,至少 gcc,给出了一个错误,

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

5 回答 5

72

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

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

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

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

于 2015-12-12T18:53:01.027 回答
12

文档中,make_shared接受将构造 T 实例的参数列表
此外,文档说:

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

因此,您可以推断您无法设置自定义删除器
为此,您必须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);
于 2015-12-12T18:38:22.093 回答
4

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

于 2015-12-12T18:32:57.237 回答
4

未指定如何make_shared获取对象的内存(它可以使用operator newormalloc或某种分配器),因此自定义删除器无法知道如何做正确的事情。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)创建的,它将在销毁时运行一些自定义代码。

于 2015-12-13T00:58:44.993 回答
0

如果您使用自定义删除器,则在创建智能指针对象时无法使用make_unique或函数。make_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

于 2018-12-20T15:44:29.830 回答