【问题标题】:unique_ptr<> v shared_ptr<> in regards to destruction policy关于销毁策略的 unique_ptr<> v shared_ptr<>
【发布时间】:2011-01-19 00:21:39
【问题描述】:

我一直在自学 C++0x 中的智能指针,但我遇到了一些让我感觉不一致的东西。具体来说,unique_ptr和shared_ptr的销毁策略是如何处理的。

对于 unique_ptr,您可以专门化 std::default_delete,从那时起,除非您明确请求不同的销毁策略,否则将使用新的默认值。

考虑以下几点:

struct some_c_type;

some_c_type *construct_some_c_type();
void destruct_some_c_type(some_c_type *);

namespace std  {
    template <> struct default_delete<some_c_type> {
        void operator()(some_c_type *ptr) {
            destruct_some_c_type(ptr);
        }
     };
}

现在,一旦到位,unique_ptr 将默认使用适当的销毁策略:

// Because of the specialization, this will use destruct_some_c_type
std::unique_ptr<some_c_type> var(construct_some_c_type());

现在将其与 shared_ptr 进行比较。使用 shared_ptr,您需要明确请求适当的销毁策略,否则默认使用 operator delete:

// error, will use operator delete 
std::shared_ptr<some_c_type> var(construct_some_c_type());

// correct, must explicitly request the destruction policy
std::shared_ptr<some_c_type> var(construct_some_c_type(),
                                 std::default_delete<some_c_type>());

两个问题。

  1. shared_ptr 需要在每次使用时指定销毁策略,或者我遗漏了什么,我是否正确?
  2. 如果我没有遗漏什么,知道为什么两者不同吗?

附:我关心这个的原因是我的公司做了很多混合 C 和 C++ 编程。 C++ 代码经常需要使用 C 风格的对象,因此指定不同的默认销毁策略的便利性对我来说非常重要。

【问题讨论】:

  • 应该是std::default_delete&lt;some_c_type&gt;()?顺便说一句,除非它在 ​​C++0x 中得到修复并且我即将发现,否则所有这三个都是令人烦恼的。
  • @GMan - 谢谢,这是一个错字。为什么你认为它们都令人烦恼(我个人觉得 unique_ptr 的设计非常简洁)?
  • @RSamuel:我的意思是令人烦恼的解析;在 C++03 中,这些都是函数声明。
  • 如果没有人回答这个问题,顺便说一句,我建议将其发布在 comp.lang.c++.moderated 上,我相信那里有人知道。如果你愿意,我会做的,我对此很好奇。
  • @GMan:在这种情况下,这确实更像是comp.std.c++的问题。这些都不是当前定义的 C++ 的一部分,至少对我来说,真正的问题是:“shared_ptr 之间的这种区别是无偿的还是有意的?”现在,它看起来可能是免费的,但是......

标签: c++ c++11


【解决方案1】:

我认为问题归结为为什么 std::shared_ptr 可以没有关联的删除器(在这种情况下它只调用delete)而不是默认构造一个std::default_delete。 (不知道。如果意图是 default_delete 用于专业化,人们会期望它被 shared_ptr 使用。)

否则会有取舍。

模板参数越少越好。 Boost 的参考资料提到,这允许工厂更改分配方案,而不会影响工厂的用户。

另一方面,unique_ptr 应该是非常轻量级的。如果删除器不是类型的一部分(GCC 使用元组,无成员对象不占用内存空间),您将如何以零空间开销存储删除器(在没有成员的仿函数的情况下)?


主观上,我认为我更喜欢:

unique_ptr<FILE, FCloser> f(fopen(x, y));

unique_ptr<FILE> f(fopen(x, y)); //default_delete<FILE> has been specialized

在第一种情况下,没有什么可猜测的。如果资源不是来自newnew[],则必须明确给出删除器。

【讨论】:

  • 我同意:显式优于隐式。
  • @UncleBens - 隐式/显式讨论的一个问题是标准特别允许隐式,这将始终编译但可能导致未定义的行为。如果您总是必须为简单的deletedelete [] 指定删除器,那可能没问题。但事实上,很容易忘记,构建会成功,这样的错误很容易错过。
  • 把它专门用于FILE之类的static_assert? :) 但即使你专攻它,你也需要记住在专精中包含标题?
  • 对于像 FILE 这样的类型,您确实需要包含头文件。但是对于本地 C 类型,我们可以在声明 C 类型的构造函数/析构函数的同一文件中包含特化。
  • 这种语法的问题在于它丑化了诸如与 C api 接口之类的东西。我希望能够做类似的事情 unique_ptr ptr(LIB_T_Make_a_T(params....), LIB_T_Destroy_a_T);其中 LIB_T_Destroy_a_T 的类型为 void(THandle*)
猜你喜欢
  • 1970-01-01
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多