【问题标题】:Typedef alias of std::shared_ptr with custom deleter带有自定义删除器的 std::shared_ptr 的 Typedef 别名
【发布时间】:2017-01-26 20:20:55
【问题描述】:

我想使用自定义删除器为 std::shared_ptr 创建一个别名。

此代码有效,但仅适用于唯一指针。我收到关于标有 [ 1 ] 的行的模板参数数量无效的错误。

我注意到 std::unique_ptrstd::shared_ptr 的模板和 ctor 参数与 herehere 列出的不同

我注意到这个问题可能与this 重复,但我不知道如何解决我的问题

#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&lt;T&gt; 的函数?

[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&lt;MyClass&gt; 别名实际上并不是shared_ptr&lt;MyClass&gt; 的别名,而是shared_ptr&lt;unique_ptr&lt;MyClass&gt;&gt; 的别名——它试图创建一个指向指针的指针(首先我认为它只是重定向构造函数)

编辑 注释掉指针指针的别名。使用 [1] 和 [3] 的想法确实没有意义甚至可能没有指针

为 shared_ptr 添加了新的(正确的)别名

编辑

整个代码现在可以工作了。所有问题都解决了。

编辑 最后一个小问题:
为什么我不能将return my_unique_ptr&lt;T&gt;(new T(std::forward&lt;Args&gt;(args)...)); 更改为return {new T(std::forward&lt;Args&gt;(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 不是。

感谢您的帮助!

【问题讨论】:

  • (1) 请发布错误消息,(2) 看起来您在 [1] 中忘记了右括号 &gt;,(3) 我在任何地方都看不到 typedef
  • shared_ptr 实际上类型擦除了它的删除器。它不是模板参数。看看复制make_shared的界面,或许吧。
  • @Rakete1111 已修复,但仍无法编译。我粘贴了错误
  • 上一次编辑的更正:为两个智能指针采用单个指针的构造函数是 explicit
  • {} 避免最麻烦的解析,禁止缩小参数。 () 在 C++11 之前工作,看起来像一个函数调用(因此在某些情况下可以用函数或 MACRO 代替)。

标签: c++ templates c++14


【解决方案1】:

你可以做一个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&lt;std::unique_ptr&lt;T/*, D*/&gt;&gt; 几乎毫无意义。

【讨论】:

  • 请添加如何使用它创建对象的示例代码,我无法让它同时与 [2] 和 [3] 一起使用
  • @Xeverous:前添加。
  • 你能解释一下我上一个问题的问题吗?
  • @Xeverous:std::unique_ptr 的构造函数采用指针是explicit,因此不允许使用这种语法。这是为了避免隐式转换,这将是非常危险的。在您的情况下,您可以使用return {new T(std::forward&lt;Args&gt;(args)...), {}}(它构建了一个默认的Deleter)。
  • 只取指针的也是explicit,取std::unique_ptr&amp;&amp;的不明确且安全(所有权转让)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 1970-01-01
  • 2020-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多