间接成员RAII:unique_ptr还是可选的?

时间:2016-03-03 07:16:17

标签: c++11 unique-ptr raii boost-optional

考虑一个具有不能直接存储的成员的类,例如,因为它没有默认构造函数,并且封闭类的构造函数没有足够的信息来创建它:

class Foo
{
public:
    Foo(){} // Default ctor
private:
    /* Won't build: no default ctor or way to call it's 
        non-default ctor at Foo's ctor. */
    Bar m_bar; 
};

显然,m_bar需要以不同的方式存储,例如通过指针。但std::unique_ptr似乎更好,因为它会自动销毁它:

    std::unique_ptr<Bar> m_bar;

但也可以使用std::experimental::optional

    std::experimenatl::optional<Bar> m_bar;

我的问题是:1。有什么权衡? 2.构建一个自动选择它们的类是否有意义?

具体来说,查看exception guarantees for the ctor of std::unique_ptrexception guarantees for the ctor of std::experimental::optional,前者必须执行动态分配和释放 - 运行时速度不利,而后者将内容存储在某些(对齐的)内存缓冲区中 - 尺寸不利。这些是唯一的权衡吗?

如果这些确实是权衡,并且假设两种类型共享足够的接口(ctor,operator*),那么用

之类的东西自动选择它们是否有意义?
 template<typename T>
 using indirect_raii = typename std::conditional<
     // 20 - arbitrary constant
     sizeof(std::experimental::optional<T>) > 
         20 + sizeof(std::exerimental::optional<T>)sizeof(std::unique_ptr<T>),
     std::unique_ptr<T>,
     std::experimental::optional<T>>::type;

(注意:返回类型有question discussing the tradeoffs between these two ,但问题和答案集中在每个传递给函数调用者的内容上,这与这些私有成员无关。)

1 个答案:

答案 0 :(得分:1)

IMO还有其他权衡取舍:

  • unique_ptr不可复制或可复制,而optional是 我想你可以做的一件事就是让indirect_RAII成为类类型,并通过调用Bar的复制文件有条件地添加定义以使其可复制,即使选择unique_ptr也是如此。 (或者相反,当它是可选的时禁用复制。)
  • optional类型可以有一个constexpr构造函数 - 您无法在编译时使用unique_ptr执行相同的操作。
  • {li> Barunique_ptr<Bar>构建时可能不完整。在optional<Bar>已知时,它不能是不完整的。在您的示例中,我猜您认为Bar已完成,因为您考虑了它的大小,但可能您可能希望使用indirect_RAII来实现一个类,但事实并非如此。
  • 即使在Bar较大的情况下,您仍然可能会发现选择std::vector<Foo>optional的效果优于unique_ptr。我希望在vector填充一次,然后迭代多次的情况下会发生这种情况。

作为一般的经验法则,您的尺寸规则可能适合您的程序中常用,但我猜测&#34;常用#34;你选择哪一个并不重要。使用indirect_RAII类型的另一种方法是,在每种情况下选择一个或另一个,并在您将利用&#34;通用接口&#34;的地方,将类型作为模板传递必要时参数。在性能关键领域,请手动做出适当的选择。