C ++移动赋值触发器首先移动构造函数

时间:2014-07-10 02:07:06

标签: c++

#include <iostream>    

class C {

public:

  ~C() { std::cout << this << " destructor\n"; }

  C() { std::cout << this << " constructor\n"; }

  C(C&& rhs) {
    std::cout << &rhs << " rhs\n";
    std::cout << this << " move constructor\n";
  }

  C& operator=(C&& rhs) {
    std::cout << &rhs << " rhs\n";
    std::cout << this << " move assignment\n";
    return *this;
  }

};

C make_one() {
  C tmp;
  return tmp;
}

int main() {

  std::cout << "move constructor:\n";
  C c1(make_one());
  std::cout << &c1 << " &c1\n\n";

  std::cout << "move assignment:\n";
  C c2;
  c2 = make_one();
  ...
}

输出:

move constructor:
000000000021F9B4 constructor         // tmp constructed in make_one()
000000000021F9B4 rhs                 // return triggers tmp being passed to ...
000000000021FA04 move constructor    // ... c1's move constructor (see below)
000000000021F9B4 destructor          // tmp destructs on going out of scope
000000000021FA04 &c1                 // (confirmed c1's address)

move assignment:
000000000021FA24 constructor         // c2 constructed
000000000021F9B4 constructor         // tmp constructed in make_one() again
000000000021F9B4 rhs                 // tmp passed to ...
000000000021FA34 move constructor    // ... a new object's move constructor
000000000021F9B4 destructor          // tmp destructs on going out of scope
000000000021FA34 rhs                 // new object passed to ...
000000000021FA24 move assignment     // .. c2's move assignment operator
000000000021FA34 destructor          // new object destructs
...

移动分配似乎首先触发移动构造函数并创建一个额外的对象。这是正常的吗?我希望(通过类比复制赋值)将tmp直接传递给c2的移动分配。

[Visual Studio Express 2013]

2 个答案:

答案 0 :(得分:7)

&#34;额外的对象&#34;被称为返回值。从函数返回值时;此值是从您提供给return语句的值构造的复制/移动。

这通常会经历 copy elision ,这可以解释为什么你没有认识到它。当发生复制省略时,行C tmp;实际上会将tmp直接构建到返回值中。复制省略也可以在其他一些情况下发生;有关全文,请参阅C ++ 11 [class.copy]#31。

据推测,您可以手动禁用复制省略,或者编译器决定不执行复制省略。 更新:您的编译器仅在发布版本上执行此特定的复制 - 请感谢Praetorian

答案 1 :(得分:0)

我完成了我的例子并留在这里,以防它帮助其他人。

#include <iostream>

class C {

public:

  ~C() { std::cout << this << " destructor\n"; }

  C() { std::cout << this << " constructor\n"; }

  C(const C& rhs) {
    std::cout << &rhs << " rhs\n";
    std::cout << this << " copy constructor\n";
  }

  C& operator=(const C& rhs) {
    std::cout << &rhs << " rhs\n";
    std::cout << this << " copy assignment\n";
    return *this;
  }

  C(C&& rhs) {
    std::cout << &rhs << " rhs\n";
    std::cout << this << " move constructor\n";
  }

  C& operator=(C&& rhs) {
    std::cout << &rhs << " rhs\n";
    std::cout << this << " move assignment\n";
    return *this;
  }

};

C make_one() {
  C tmp;
  return tmp;
}

int main() {

  std::cout << "c1's constructor:\n";
  C c1;

  std::cout << "\nc1 passed to c2's copy constructor:\n";
  C c2(c1);
  std::cout << &c2 << " &c2\n\n";

  std::cout << "c3 and c4's constructors:\n";
  C c3, c4;
  std::cout << "c3 passed to c4's copy assignment:\n";
  c4 = c3;

  std::cout << "\ntmp constructed, passed to c5's move constructor then destructed\n";
  C c5(make_one());
  std::cout << &c5 << " &c5\n\n";

  std::cout << "c6's constructor:\n";
  C c6;
  std::cout << "tmp constructed, passed to return value's move constructor then destructed\n"
               "return value passed to c6's move assignment then destructed:\n";
  c6 = make_one();

  return 0;
}

调试输出:

c1's constructor:
000000000013F9B4 constructor

c1 passed to c2's copy constructor:
000000000013F9B4 rhs
000000000013F9D4 constructor
000000000013F9D4 &c2

c3 and c4's constructors:
000000000013F9F4 constructor
000000000013FA14 constructor
c3 passed to c4's copy assignment:
000000000013F9F4 rhs
000000000013FA14 copy assignment

tmp constructed, passed to c5's move constructor then destructed
000000000013F964 constructor
000000000013F964 rhs
000000000013FA34 move constructor
000000000013F964 destructor
000000000013FA34 &c5

c6's constructor:
000000000013FA54 constructor
tmp constructed, passed to return value's move constructor then destructed
return value passed to c6's move assignment then destructed:
000000000013F964 constructor
000000000013F964 rhs
000000000013FA64 move constructor
000000000013F964 destructor
000000000013FA64 rhs
000000000013FA54 move assignment
000000000013FA64 destructor
...

释放输出(显示移动构造函数的省略):

c1's constructor:
00000000001BFC41 constructor

c1 passed to c2's copy constructor:
00000000001BFC41 rhs
00000000001BFC40 constructor
00000000001BFC40 &c2

c3 and c4's constructors:
00000000001BFC78 constructor
00000000001BFC70 constructor
c3 passed to c4's copy assignment:
00000000001BFC78 rhs
00000000001BFC70 copy assignment

tmp constructed, passed to c5's move constructor then destructed
00000000001BFC68 constructor
00000000001BFC68 &c5

c6's constructor:
00000000001BFC60 constructor
tmp constructed, passed to return value's move constructor then destructed
return value passed to c6's move assignment then destructed:
00000000001BFC42 constructor
00000000001BFC42 rhs
00000000001BFC60 move assignment
00000000001BFC42 destructor
....