简体   繁体   中英

Does std::is_nothrow_move_constructible require a noexcept destructor?

The following code fails to compile with Visual Studio 2017 (15.5), gcc 6.4.0 and clang 4.0.1, ie the static assertions are failing:

struct Type
{
  Type(Type&&) noexcept {}

  ~Type() noexcept(false) {}
};

static_assert(std::is_nothrow_move_constructible<Type>::value, "Type should be nothrow-move-constructible");
static_assert(std::is_nothrow_constructible<Type, Type&&>::value, "Type should be nothrow-constructible from Type&&");

Is this correct by the C++ standard? Does std::is_nothrow_move_constructible require a noexcept destructor? Why?

If I use this such as:

Type a;
Type b(std::move(a));  

the destructor of a is not called during the second statement.

We can see std::is_nothrow_move_constructible is defined in terms of is_nothrow_constructible_v . So this ends up being covered by LWG issue 2116: is_nothrow_constructible and destructors which is not resolved, so it is not a bug unless the issue get resolved differently then how the implementations currently act.

It opens with the following discussion:

IMO if we specified is_[nothrow_]constructible in terms of a variable declaration whose validity requires destructibility, it is clearly a bug in our specification and a failure to realize the actual original intent. The specification should have been in terms of placement-new.

Daniel: At the time of the specification this was intended and the solution is not done by removing the destruction semantics of is_constructible.

The design of is_constructible was also impacted by the previous Constructible concept that explicitly contained destruction semantics , because during conceptification of the library it turned out to simplify the constraints in the library because you did not need to add Destructible all the time. It often was implied but never spoken out in C++03.

Pure construction semantics was considered as useful as well, so HasConstructor did also exist and would surely be useful as trait as well.

Another example that is often overlooked: This also affects wrapper types like pair, tuple, array that contain potentially more than one type: This is easy to understand if you think of T1 having a deleted destructor and T2 having a constructor that may throw: Obviously the compiler has potentially need to use the destructor of T1 in the constructor of std::pair to ensure that the core language requirements are satisfied (All previous fully constructed sub-objects must be destructed).

The core language also honors this fact in [class.copy] p11:

A defaulted copy/move constructor for a class X is defined as deleted (9.4.3 [dcl.fct.def.delete]) if X has:
[…]
— any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor,
[…]

Dave: This is about is_nothrow_constructible in particular. The fact that it is foiled by not having a noexcept dtor is a defect.

it concludes with:

Ville would like "an evolution group" to take a look at this issue.

and from this gcc bug report at least gcc will be waiting for the issue to be resolved.

Also see Non-trivial destructor make class non-trivially-constructible which covers some other references to a related issue. Also note the clang bug for this .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM