programing

`= default` 이동 생성자는 멤버 단위 이동 생성자와 동일합니까?

nasanasas 2020. 9. 10. 07:58
반응형

`= default` 이동 생성자는 멤버 단위 이동 생성자와 동일합니까?


이것은

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB}               { }
    Example(const Example& mE) : a{mE.a}, b{mE.b}        { }
    Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
    Example& operator=(const Example& mE) { a = mE.a; b = mE.b; return *this; } 
    Example& operator=(Example&& mE)      { a = move(mE.a); b = move(mE.b); return *this; } 
}

이것에 해당

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB} { }
    Example(const Example& mE)            = default;
    Example(Example&& mE)                 = default;
    Example& operator=(const Example& mE) = default;
    Example& operator=(Example&& mE)      = default;
}

?


예, 둘 다 동일합니다.

그러나

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB} { }
    Example(const Example& mE)            = default;
    Example(Example&& mE)                 = default;
    Example& operator=(const Example& mE) = default;
    Example& operator=(Example&& mE)      = default;
}

이 버전에서는 본문 정의를 건너 뛸 수 있습니다.

그러나 다음을 선언 할 때 몇 가지 규칙을 따라야합니다 explicitly-defaulted-functions.

8.4.2 명시 적으로 기본값이 지정된 함수 [dcl.fct.def.default]

다음 형식의 함수 정의 :

  attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt = default ;

명시 적 기본값 정의 라고합니다 . 명시 적으로 기본값이 설정된 함수는

  • 특별한 멤버 함수 여야합니다.

  • 선언 된 함수 유형이 동일합니다 (다른 ref 한정자 를 제외하고 복사 생성자 또는 복사 할당 연산자의 경우 매개 변수 유형은 "비상 수에 대한 참조"일 수 있음을 제외하고 T, 여기서는 T멤버 함수의 이름입니다). class) 암시 적으로 선언 된 것처럼

  • 기본 인수가 없습니다.


예, 기본 이동 생성자는 기본 및 멤버의 멤버 별 이동을 수행하므로 다음과 같습니다.

Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }

다음과 같습니다.

Example(Example&& mE)                 = default;

우리가로 이동하여 볼 수 있습니다 초안 C ++ 11 표준 섹션 12.8 클래스를 복사 및 이동이 객체 문단 13 (라고 강조 광산 향후 ) :

기본값으로 설정되고 삭제 된 것으로 정의되지 않은 복사 / 이동 생성자 는 odrused (3.2)이거나 첫 번째 선언 이후에 명시 적으로 기본값이 지정 될 때 암시 적으로 정의 됩니다. [참고 : 복사 / 이동 생성자는 구현에서 odr-use (3.2, 12.2)를 제거하더라도 암시 적으로 정의됩니다. —end note] [...]

그리고 다음과 같은 단락 15 :

암시 적으로 정의 복사 / 이동 생성자 비 노조 클래스 X에 대한 수행의 기초 및 회원의 memberwise의 복사 / 이동 . [참고 : 비 정적 데이터 멤버의 중괄호 또는 같음 이니셜 라이저는 무시됩니다. 12.6.2의 예도 참조하십시오. —end note] 초기화 순서는 사용자 정의 생성자의 기본 및 멤버 초기화 순서와 동일합니다 (12.6.2 참조). x를 생성자의 매개 변수이거나 이동 생성자의 경우 매개 변수를 참조하는 xvalue가되도록하십시오. 각 기본 또는 비 정적 데이터 멤버는 해당 유형에 적합한 방식으로 복사 / 이동됩니다.

  • 멤버가 배열이면 각 요소는 x의 해당 하위 객체로 직접 초기화됩니다.
  • 멤버 m에 rvalue 참조 유형 T &&가 있으면 static_cast (xm)로 직접 초기화됩니다.
  • otherwise, the base or member is direct-initialized with the corresponding base or member of x.

Virtual base class subobjects shall be initialized only once by the implicitly-defined copy/move constructor (see 12.6.2).


Is a =default move constructor equivalent to a member-wise move constructor?

Yes. Update: Well, not always. Look at this example:

#include <iostream>

struct nonmovable
{
    nonmovable() = default;

    nonmovable(const nonmovable  &) = default;
    nonmovable(      nonmovable &&) = delete;
};

struct movable
{
    movable() = default;

    movable(const movable  &) { std::cerr << "copy" << std::endl; }
    movable(      movable &&) { std::cerr << "move" << std::endl; }
};

struct has_nonmovable
{
    movable    a;
    nonmovable b;

    has_nonmovable() = default;

    has_nonmovable(const has_nonmovable  &) = default;
    has_nonmovable(      has_nonmovable &&) = default;
};

int main()
{
    has_nonmovable c;
    has_nonmovable d(std::move(c)); // prints copy
}

It prints:

copy

http://coliru.stacked-crooked.com/a/62c0a0aaec15b0eb

You declared defaulted move constructor, but copying happens instead of moving. Why? Because if a class has even a single non-movable member then the explicitly defaulted move constructor is implicitly deleted (such a pun). So when you run has_nonmovable d = std::move(c), the copy constructor is actually called, because the move constructor of has_nonmovable is deleted (implicitly), it just doesn't exists (even though you explicitly declared the move constructor by expression has_nonmovable(has_nonmovable &&) = default).

But if the move constructor of non_movable was not declared at all, the move constructor would be used for movable (and for every member that has the move constructor) and the copy constructor would be used for nonmovable (and for every member that does not define the move constructor). See the example:

#include <iostream>

struct nonmovable
{
    nonmovable() = default;

    nonmovable(const nonmovable  &) { std::cerr << "nonmovable::copy" << std::endl; }
    //nonmovable(      nonmovable &&) = delete;
};

struct movable
{
    movable() = default;

    movable(const movable  &) { std::cerr << "movable::copy" << std::endl; }
    movable(      movable &&) { std::cerr << "movable::move" << std::endl; }
};

struct has_nonmovable
{
    movable    a;
    nonmovable b;

    has_nonmovable() = default;

    has_nonmovable(const has_nonmovable  &) = default;
    has_nonmovable(      has_nonmovable &&) = default;
};

int main()
{
    has_nonmovable c;
    has_nonmovable d(std::move(c));
}

It prints:

movable::move
nonmovable::copy

http://coliru.stacked-crooked.com/a/420cc6c80ddac407

Update: But if you comment out the line has_nonmovable(has_nonmovable &&) = default;, then copy will be used for both members: http://coliru.stacked-crooked.com/a/171fd0ce335327cd - prints:

movable::copy
nonmovable::copy

So probably putting =default everywhere still makes sense. It doesn't mean that your move expressions will always move, but it makes chances of this higher.

One more update: But if comment out the line has_nonmovable(const has_nonmovable &) = default; either, then the result will be:

movable::move
nonmovable::copy

So if you want to know what happens in your program, just do everything by yourself :sigh:


apart very pathological cases ... YES.

To be more precise, you have also to considered eventual bases Example may have, with exact same rules. First the bases -in declaration order- then the members, always in declaration order.

참고URL : https://stackoverflow.com/questions/18290523/is-a-default-move-constructor-equivalent-to-a-member-wise-move-constructor

반응형