在C ++ 17中,如果std::optional
在[optional.object.dtor]中可以轻易破坏,则新T
强制要求它是可以轻易破坏的:
~optional();
1 效果:如果is_trivially_destructible_v<T> != true
和*this
包含值,请拨打val->T::~T()
。
2 备注:如果is_trivially_destructible_v<T> == true
那么这个析构函数应该是一个简单的析构函数。
因此,这个潜在的实现片段将不符合标准:
template <class T>
struct wrong_optional {
union { T value; };
bool on;
~wrong_optional() { if (on) { value.~T(); } }
};
我的问题是:这项任务的优势是什么?据推测,对于简单的可破坏类型,编译器可以发现value.~T()
是无操作并且不为wrong_optional<T>::~wrong_optional()
发出代码。
答案 0 :(得分:15)
std::optional
已有constexpr
constructors。当它的析构函数是微不足道的时候,它是literal type。只能在常量表达式中创建和操作文字类型的对象。
答案 1 :(得分:9)
一种可以轻易破坏的类型是它自己的奖励。以下是使用简单析构函数的一些优点:
该类型可以轻易复制。这使得该类型有资格进行各种优化。 Visual Studio的标准库实现有一个number of optimizations来处理这些类型。
不打扰调用易于破坏的类型的析构函数是合法的。您只需取消分配存储空间即可。这是一种低级别的事情,但它可以有优势。它是允许实现进行上述优化的部分原因。
具有普通析构函数的类型可以是文字类型,因此是可以在编译时构造和操作的对象。
optional<T>
的界面试图尽可能不干扰T
的行为。因此,如果您可以使用T
执行某些操作,那么您应该能够使用optional<T>
执行相同的操作。除非有充分的理由不这样做。
答案 2 :(得分:0)
Per this Q/A,一个尚未提及并且值得一提的具体原因是:一个可以轻易复制并且可以轻易破坏的类型允许它在ABI中的寄存器中传递(参见Agner Fog's calling conventions)。这可能会对生成的代码产生重大影响。一个简单的功能,如:
std::optional<int> get() { return {42}; }
如果类型不是可复制/可破坏的,可能会发出以下代码:
mov rax, rdi
mov DWORD PTR [rdi], 42
mov BYTE PTR [rdi+4], 1
ret
但是如果是这样的话,可以发出以下内容:
movabs rax, 4294967338
ret
那肯定更好。