Alternatively, is there an example of a type with a copy constructor that can throw, but is nontheless trivial?
And if not, does that imply that the is_nothrow_copy_constructible_v<T>
should be true whenever is_trivially_copy_constructible_v<T>
is true?
Note that according to the standard (latest draft [23.15.4.3]), for a type T to be nothrow copyable, we need the expression T t(declval<const T&>());
to be a well-formed variable definition that is known not to throw any exceptions. This wording seems to be somewhat vauge to me - what does it mean for something to be known? Should the noexcept
specifier be sufficient to establish that knowledge? or maybe the determination is left to the implementation?
Edit: I realize there's a difference between being trivially copyable, and being trivially copy constructible. My focus is on the latter.
A trivially copyable class is a class that: has no non-trivial copy constructors, has no non-trivial move constructors, has no non-trivial copy assignment operators, has no non-trivial move assignment operators, and has a trivial destructor.
A std::function might allocate memory for captured variables. As with any other class which allocates memory, it's not trivially copyable.
Trivially copyable types have no non-trivial copy operations, move operations, or destructors. Generally, a copy operation is considered trivial if it can be implemented as a bitwise copy. Both built-in types and arrays of trivially copyable types are trivially copyable.
std::pair has a non-trivial copy-assignment and move-assignment operator. This prevents it from being trivially copyable. Since C++17, if one of the two contained types is not assignable, then the copy/move assignment operator is defined as deleted, which lifts this restriction on being trivially copyable.
Does being trivially copyable imply being nothrow copyable?
No. For example:
struct X {
X(X&& ) = default;
X(X const& ) = delete;
};
This type is trivially copyable, but not nothrow copyable... or even copyable at all.
However, given that a type is copyable†and trivially copyable, then it must be copyable without throwing (any potential exception would have to come from a non-trivial copy, which can't exist).
†Simply defaulting a copy constructor but marking it noexcept(false)
defines it as deleted, so such a type would not be copyable.
On a compiler that implements DR2171:
struct X {
X(X&) = default;
template<class U> X(U&&){ throw 1; }
};
static_assert(std::is_trivially_copyable_v<X>, "");
static_assert(std::is_copy_constructible_v<X>, "");
static_assert(!std::is_nothrow_copy_constructible_v<X>, "");
static_assert(!std::is_trivially_copy_constructible_v<X>, "");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With