1

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

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需要以不同方式存储,例如通过指针。不过, Astd::unique_ptr似乎更好,因为它会自动破坏它:

    std::unique_ptr<Bar> m_bar;

不过,也可以使用std::experimental::optional

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

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

具体来说,查看ctor ofstd::unique_ptr异常保证和 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;

(注意:有一个问题讨论了这两者作为返回类型之间的权衡,但问题和答案集中在每个传递给函数调用者的内容上,这与这些私有成员无关。)

4

1 回答 1

1

IMO 这里还有其他权衡:

  • unique_ptr不可复制或可复制分配,而optionalis.
    我想您可以做的一件事是创建indirect_RAII一个类类型并有条件地添加定义,以通过调用 's 复制 ctor 使其可Bar复制,即使unique_ptr被选中也是如此。(或者相反,在可选时禁用复制。)
  • optional类型可以有一个constexpr构造函数——你不能unique_ptr在编译时用 a 做同样的事情。
  • Barunique_ptr<Bar>在构建时可能是不完整的。在已知的时间,它不可能是不完整的optional<Bar>。在您的示例中,我猜您假设这Bar是完整的,因为您采用了它的大小,但是您可能希望indirect_RAII在不是这种情况的情况下使用实现一个类。
  • 即使在很大的情况下Bar,您仍然可能会发现 eg在选择时比在选择时std::vector<Foo>执行得更好。我希望在填充一次然后迭代多次的情况下会发生这种情况。 optionalunique_ptrvector

作为一般的经验法则,您的大小规则可能适合您的程序中的常见用途,但我想对于“常见用途”,您选择哪一个并不重要。使用您的indirect_RAII类型的另一种选择是,在每种情况下只选择一个,并且在您可以利用“通用接口”的地方,在必要时将类型作为模板参数传递。在性能关键领域,手动做出适当的选择。

于 2016-03-03T09:39:39.123 回答