This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-10-26


1402. Move functions too often deleted

Section: 11.4.5.3  [class.copy.ctor]     Status: CD3     Submitter: Daniel Krügler     Date: 2011-10-03

[Moved to DR status at the April, 2013 meeting as paper N3667.]

Paragraphs 11 and 23 of 11.4.5.3 [class.copy.ctor] make a defaulted move constructor and assignment operator, respectively, deleted if there is a subobject with no corresponding move function and for which the copy operation is non-trivial. This seems excessive and unnecessary. For example:

    template<typename T>
     struct wrap
     {
      wrap() = default;

    #ifdef USE_DEFAULTED_MOVE
      wrap(wrap&&) = default;
    #else
      wrap(wrap&& w) : t(static_cast<T&&>(w.t)) { }
    #endif

      wrap(const wrap&) = default;

      T t;
     };

    struct S {
      S(){}
      S(const S&){}
      S(S&&){}
    };

    typedef wrap<const S> W;

    W get() { return W(); }  // Error, if USE_DEFAULTED_MOVE is defined, else OK

In this example the defaulted move constructor of wrap is selected by overload resolution, but this move-constructor is deleted, because S has no trivial copy-constructor.

I think that we overshoot here with the delete rules: I see no problem for the defaulted move-constructor in this example. Our triviality-deduction rules already cover this case (11.4.5.3 [class.copy.ctor] paragraph 12: W::W(W&&) is not trivial) and our exception-specification rules (14.5 [except.spec] paragraph 14) already correctly deduce a noexcept(false) specification for W::W(W&&).

It would still be OK to prevent that a move-constructor would be generated for the following example where no user-declared defaulted copy/move members are present:

    template<typename T>
     struct wrap_2
     {
      wrap_2() = default;
      T t;
     };

    typedef wrap_2<const S> W2;

    W2 get() { return W2(); }  // OK, selects copy constructor

if we want. This would mean that we add a new bullet to 11.4.5.3 [class.copy.ctor] paragraph 9 and paragraph 20.

Proposed resolution (February, 2012):

  1. Change 11.4.5.3 [class.copy.ctor] paragraph 9 as follows:

  2. If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

    [Note:...

  3. Change 11.4.5.3 [class.copy.ctor] paragraph 11 as follows:

  4. An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy/move constructor for a class X is defined as deleted (9.5.3 [dcl.fct.def.delete]) if X has:

  5. Change 11.4.5.3 [class.copy.ctor] paragraph 20 as follows:

  6. If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if

    Example:...

  7. Change 11.4.5.3 [class.copy.ctor] paragraph 23 as follows:

  8. A defaulted copy/move assignment operator for class X is defined as deleted if X has:

Additional notes (August, 2012):

The proposed resolution was extensively discussed and additional alternatives were suggested. A paper is being produced for the October, 2012 meeting describing the various options, so the issue has been returned to "review" status to wait for the outcome of that deliberation.

See also the discussion of issue 1491 for additional considerations.

Proposed resolution (December, 2012):

  1. Change 11.4.5.3 [class.copy.ctor] paragraph 9 as follows:

  2. If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

    [Note:...

  3. Change 11.4.5.3 [class.copy.ctor] paragraph 11 as follows:

  4. ...A defaulted copy/move constructor for a class X is defined as deleted (9.5.3 [dcl.fct.def.delete]) if X has:

    A defaulted move constructor that is defined as deleted is ignored by overload resolution (12.2 [over.match]). [Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. —end note]

  5. Change 11.4.5.3 [class.copy.ctor] paragraph 20 as follows:

  6. If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if

    [Example:...

  7. Change 11.4.5.3 [class.copy.ctor] paragraph 23 as follows:

  8. A defaulted copy/move assignment operator for class X is defined as deleted if X has:

    A defaulted move assignment operator that is defined as deleted is ignored by overload resolution (12.2 [over.match], 12.3 [over.over]).

This resolution also resolves issue 1491.