使用自定义deleter类型定义std::shared_ptr的别名
Typedef alias of std::shared_ptr with custom deleter
我想用自定义deleter为std::shared_ptr
创建一个别名。
此代码有效,但仅适用于唯一指针。我收到一个错误,关于用[1]标记的行的模板参数数量无效。
我注意到std::unique_ptr
和std::shared_ptr
的模板和ctor参数在这里和这里列出的中有所不同
我注意到这个问题可能与此重复,但我不知道如何解决我的问题
#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 ctorn";
}
~MyClass()
{
std::cout << "Default dtorn";
}
void Drop()
{
std::cout << "Custom deletern";
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]
如何让它知道使用我的deleter?
对于[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
的ctor是显式的,而std::shared_ptr
的ctor不是显式的。
感谢SO的帮助
您可以执行my_make_shared
,类似于:
template <class T, class... Args>
std::shared_ptr<T> my_make_shared(Args&&... args)
{
return {new T(std::forward<Args>(args)...), Deleter<T>{}};
}
用法:
std::shared_ptr<MyClass> p(my_make_shared<MyClass>());
对于[3],它应该是:
std::shared_ptr<MyClass> p(my_make_unique<MyClass>());
注意,std::shared_ptr<std::unique_ptr<T/*, D*/>>
基本上是没有意义的。
- 部分定义/别名模板模板参数
- 如何在C++20中创建模板别名的推导指南
- 告诉c++编译器该参数没有别名
- boost::spirit::karma 替代生成器,带有 boost::variant 由字符串和字符串别名组成
- 继承模板类中的类型别名
- 别名模板的专业化 C++11 中没有开销的最佳替代方案
- 为什么 GCC 在使用类型别名时处理 const reinterpret_cast不同?
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 为什么我们不能重复使用具有不同模板参数的别名模板标识符?
- C++模板/别名 - 模板参数列表中参数 1 处的类型/值不匹配
- 如何使用类型别名从模板化类中隐藏模板列表
- 模板模板参数和模板别名:编译器错误?
- 使用定义函数模板别名
- 为模板参数包添加别名
- 如何检测类型类型别名?
- C++类型别名,其中值被替换
- C++使用默认模板参数键入别名和转发声明
- 在Qt中注册自定义元类型的别名类型
- 缺少别名模板C++参数列表
- 使用外部定义的模板类型作为模板参数的更通用模板的模板别名