我希望为std::shared_ptr
创建一个自定义删除器的别名。
这段代码可以工作,但只适用于独占式指针。对于标记为[1]的行,我会收到关于无效模板参数数量的错误信息。
我注意到std::unique_ptr
和std::shared_ptr
的模板和构造函数参数不同,如此处所列(参见此处)和(参见此处)
我注意到这个问题可能是这个的重复,但我无法解决我的问题
#include <memory>
#include <iostream>
template<class T>
struct Deleter {
void operator()(T* p) const noexcept {
p->Drop(); // SFINAE
};
};
template <class T>
using my_unique_ptr = std::unique_ptr<T, Deleter<T>>;
//template <class T>
//using my_shared_ptr = std::shared_ptr<T, Deleter<T>>; // [1] does not work
//using my_shared_ptr = std::shared_ptr<my_unique_ptr<T>>; // this is pointless
template <class T>
using my_shared_ptr = std::shared_ptr<T>;
template <class T, class... Args>
my_unique_ptr<T> my_make_unique(Args&&... args)
{
return my_unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template <class T, class... Args>
std::shared_ptr<T> my_make_shared(Args&&... args)
{
return {new T(std::forward<Args>(args)...), Deleter<T>{}};
// return {new T(std::forward<Args>(args)...), Deleter<T>()}; this also works
}
class MyClass{
public:
MyClass()
{
std::cout << "Default ctor\n";
}
~MyClass()
{
std::cout << "Default dtor\n";
}
void Drop()
{
std::cout << "Custom deleter\n";
delete this;
}
};
int main()
{
{
my_unique_ptr<MyClass> p1(new MyClass);
my_unique_ptr<MyClass> p2 = my_make_unique<MyClass>();
}
{
// my_shared_ptr<MyClass> p(new MyClass) // [2] does not work
// my_shared_ptr<MyClass> p(my_make_unique<MyClass>()); // [3] does not work
std::shared_ptr<MyClass> p1 = my_make_shared<MyClass>(); // [4] works
my_shared_ptr<MyClass> p2 = my_make_shared<MyClass>();
}
}
对于 [ 2 ]
我该如何告诉它使用我的删除器?
对于 [ 3 ]
如果 [ 2 ] 不可行,那么我应该如何创建一个能够为我创建 my_shared_ptr<T>
的函数?
错误信息对于 [ 1 ]
main.cpp:15:51: error: wrong number of template arguments (2, should be 1)
using my_shared_ptr = std::shared_ptr<T, Deleter<T>> // does not work
^~
In file included from /usr/local/include/c++/6.3.0/bits/shared_ptr.h:52:0,
from /usr/local/include/c++/6.3.0/memory:82,
from main.cpp:1:
/usr/local/include/c++/6.3.0/bits/shared_ptr_base.h:343:11: note: provided for 'template<class _Tp> class std::shared_ptr'
class shared_ptr;
^~~~~~~~~~
[ 2 ]的错误
In file included from /usr/local/include/c++/6.3.0/bits/shared_ptr.h:52:0,
from /usr/local/include/c++/6.3.0/memory:82,
from main.cpp:1:
/usr/local/include/c++/6.3.0/bits/shared_ptr_base.h: In instantiation of 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Tp1*) [with _Tp1 = MyClass; _Tp = std::unique_ptr<MyClass, Deleter<MyClass> > __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]':
/usr/local/include/c++/6.3.0/bits/shared_ptr.h:117:32: required from 'std::shared_ptr<_Tp>::shared_ptr(_Tp1*) [with _Tp1 = MyClass; _Tp = std::unique_ptr<MyClass, Deleter<MyClass> >]'
main.cpp:48:45: required from here
/usr/local/include/c++/6.3.0/bits/shared_ptr_base.h:885:39: error: cannot convert 'MyClass*' to 'std::unique_ptr<MyClass, Deleter<MyClass> >*' in initialization
: _M_ptr(__p), _M_refcount(__p)
^
编辑
添加了my_make_shared
函数, 现在[4]已经可以编译通过了。
编辑
我注意到(通过观察错误)我的别名shared_ptr<MyClass>
并不是真正的shared_ptr<MyClass>
,而是shared_ptr<unique_ptr<MyClass>>
的别名 - 它试图创建一个指向指针的指针(一开始我以为它只是重定向构造函数)
编辑 将指向指针的别名注释掉。使用[1]和[3]的想法确实是毫无意义的甚至是没有指针的。
添加新的(正确的)shared_ptr别名
编辑
整个代码现在都可以工作了。所有问题都解决了。
编辑
最后,有个小问题:
为什么我不能把return my_unique_ptr<T>(new T(std::forward<Args>(args)...));
改成return {new T(std::forward<Args>(args)...)};
?
我得到了这个错误:
main.cpp: In instantiation of 'my_unique_ptr<T> my_make_unique(Args&& ...) [with T = MyClass; Args = {}; my_unique_ptr<T> = std::unique_ptr<MyClass, Deleter<MyClass> >]':
main.cpp:56:61: required from here
main.cpp:26:63: error: converting to 'my_unique_ptr<MyClass> {aka std::unique_ptr<MyClass, Deleter<MyClass> >}' from initializer list would use explicit constructor 'std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = MyClass; _Dp = Deleter<MyClass> std::unique_ptr<_Tp, _Dp>::pointer = MyClass*]'
return {new T(std::forward<Args>(args)...)};
^
了解到std::unique_ptr
的构造函数是明确的(explicit),但std::shared_ptr
的构造函数不是。
非常感谢SO提供的帮助!
>
。 (3) 我没有看到任何typedef
。 - Rakete1111shared_ptr
实际上是类型擦除其删除器,而不是模板参数。也许可以看一下复制make_shared
的接口。 - BoBTFishDeleter<T>{}
可以被Deleter<T>()
替代 - 哪个更符合惯例? - Xeverous