考虑一个具有不能直接存储的成员的类,例如,因为它没有默认构造函数,并且封闭类的构造函数没有足够的信息来创建它:
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_ptr
和exception 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 ,但问题和答案集中在每个传递给函数调用者的内容上,这与这些私有成员无关。)
答案 0 :(得分:1)
IMO还有其他权衡取舍:
unique_ptr
不可复制或可复制,而optional
是
我想你可以做的一件事就是让indirect_RAII
成为类类型,并通过调用Bar
的复制文件有条件地添加定义以使其可复制,即使选择unique_ptr
也是如此。 (或者相反,当它是可选的时禁用复制。)optional
类型可以有一个constexpr
构造函数 - 您无法在编译时使用unique_ptr
执行相同的操作。 Bar
在unique_ptr<Bar>
构建时可能不完整。在optional<Bar>
已知时,它不能是不完整的。在您的示例中,我猜您认为Bar
已完成,因为您考虑了它的大小,但可能您可能希望使用indirect_RAII
来实现一个类,但事实并非如此。
Bar
较大的情况下,您仍然可能会发现选择std::vector<Foo>
时optional
的效果优于unique_ptr
。我希望在vector
填充一次,然后迭代多次的情况下会发生这种情况。 作为一般的经验法则,您的尺寸规则可能适合您的程序中常用,但我猜测&#34;常用#34;你选择哪一个并不重要。使用indirect_RAII
类型的另一种方法是,在每种情况下选择一个或另一个,并在您将利用&#34;通用接口&#34;的地方,将类型作为模板传递必要时参数。在性能关键领域,请手动做出适当的选择。