由于C ++ 11,由于几个原因,开发人员倾向于将智能指针类用于动态生命周期对象。对于那些新的智能指针类,标准,甚至建议不使用new
之类的运算符,他们建议使用make_shared
或make_unique
来避免一些错误。
如果我们想使用智能指针类,例如shared_ptr
,我们可以构建一个类似的,
shared_ptr<int> p(new int(12));
我们还希望将自定义删除器传递给智能指针类
shared_ptr<int> p(new int(12), deleter);
另一方面,如果我们想使用make_shared
来分配,例如。 int
,而不是使用new
和shared_ptr
构造函数,就像上面的第一个表达式一样,我们可以使用
auto ip = make_shared<int>(12);
但是,如果我们也希望将自定义删除工具传递给make_shared
,那么有没有正确的方法呢?看起来像编译器,至少gcc,给出了错误,
auto ip = make_shared<int>(12, deleter);
答案 0 :(得分:46)
正如其他人所说,make_shared
不能与自定义删除器一起使用。但我想解释一下原因。
存在自定义删除器是因为您以某种特殊方式分配了指针,因此您需要能够以相应的特殊方式释放它。好吧,make_shared
用new
分配指针。分配有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 new
或malloc
或某种分配器),因此自定义删除器无法知道如何做正确的事。 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_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函数是new
和delete
的包装器,如果要自定义删除器,则必须提供自己的new
和delete