问题
In C++17, the new std::optional
mandates that it be trivially destructible if T
is trivially destructible in [optional.object.dtor]:
~optional();
1 Effects: Ifis_trivially_destructible_v<T> != true
and*this
contains a value, callsval->T::~T()
.
2 Remarks: Ifis_trivially_destructible_v<T> == true
then this destructor shall be a trivial destructor.
So this potential implementation fragment would be non-conforming to the standard:
template <class T>
struct wrong_optional {
union { T value; };
bool on;
~wrong_optional() { if (on) { value.~T(); } }
};
My question is: what is the advantage of this mandate? Presumably, for trivially destructible types, the compiler can figure out that value.~T()
is a no-op and emit no code for wrong_optional<T>::~wrong_optional()
.
回答1:
std::optional
already has constexpr constructors. When its destructor is trivial, it is a literal type. Only objects of literal types can be created and manipulated in constant expressions.
回答2:
A type being trivially destructible is its own reward. Here are just a few of the advantages of having a trivial destructor:
The type can be trivially copyable. And this make the type eligible for all kinds of optimizations. Visual Studio's standard library implementation has a number of optimizations for dealing with such types.
It's legal to not bother calling the destructor of trivially destructible types. You can just deallocate their storage. This is kind of a low-level thing to do, but it can have advantages. It's part of what allows implementations to do those optimizations above.
Types with trivial destructors can be literal types, and are thus objects which can be constructed and manipulated at compile time.
optional<T>
's interface is attempting not to interfere with the behavior of T
as much as possible. So if you could do something with T
, then you ought to be able to do that same thing with optional<T>
. Unless there is a really good reason not to.
回答3:
Per this Q/A, one specific reason not yet mentioned and worth mentioning is: a type being trivially copyable and trivially destructible allows it to be passed in registers in the ABI (see Agner Fog's calling conventions). This can have significant effects on the generated code. A simple function like:
std::optional<int> get() { return {42}; }
Might emit the following code if the type isn't trivially copyable/destructible:
mov rax, rdi
mov DWORD PTR [rdi], 42
mov BYTE PTR [rdi+4], 1
ret
But could emit just the following if it were:
movabs rax, 4294967338
ret
That's definitely better.
来源:https://stackoverflow.com/questions/41897418/significance-of-trivial-destruction