我有一个简单的结构,定义了所有构造函数。 它有一个 int 变量,每个构造函数和赋值运算符打印 *this 的地址、int 的当前值和 int 的新值。 移动和复制赋值运算符和构造函数也会打印传递值的地址。
#include <iostream>
struct X
{
int val;
void out(const std::string& s, int nv, const X* from = nullptr)
{
std::cout<<this<<"->"<<s<<": "<<val<<" ("<<nv<<")";
if (from)
std::cout<<", from: ["<<from<<"]";
std::cout<<"\n";
}
X(){out("simple ctor X()",0); val = 0;}
X(int v){out("int ctor X(int)", v);val = v; }
X(const X& x){out("copy ctor X(X&)", x.val, &x);val = x.val; };
X&operator = (const X& x){out("copy X::operator=()", x.val, &x); val = x.val; return *this;}
~X(){out("dtor ~X", 0);}
X&operator = (X&& x){out("move X::operator(&&)", x.val, &x); val = x.val; return *this;}
X(X&& x){out("move ctor X(&&x)", x.val, &x);val = x.val;}
};
X copy(X a){return a;}
int main(int argc, const char * argv[]) {
X loc{4};
X loc2;
std::cout<<"before copy\n";
loc2 = copy(loc);
std::cout<<"copy finish\n";
}
输出:
0xffdf7278->int ctor X(int): 134523184 (4) 0xffdf727c->simple ctor X(): 134514433 (0) before copy 0xffdf7280->copy ctor X(X&): 1433459488 (4), from: [0xffdf7278] 0xffdf7284->move ctor X(&&x): 1433437824 (4), from: [0xffdf7280] 0xffdf727c->move X::operator(&&): 0 (4), from: [0xffdf7284] 0xffdf7284->dtor ~X: 4 (0) 0xffdf7280->dtor ~X: 4 (0) copy finish 0xffdf727c->dtor ~X: 4 (0) 0xffdf7278->dtor ~X: 4 (0)
(在本例中)创建地址为 0xffdf7284 的附加对象的目的是什么?
最佳答案
如果你看copy elision rules from cppreference.com ,您可以注意到,在两种情况下,编译器需要省略类对象的复制和移动构造函数即使复制/移动构造函数和析构函数具有可观察到的副作用(您的做,由于打印输出)。第一个显然与本案无关。第二个是
In a function call, if the operand of a return statement is a prvalue and the return type of the function is the same as the type of that prvalue.
给出的例子是:
T f() { return T{}; }
T x = f();
这似乎更相关,但是请注意,在您的情况下,return
语句的操作数不是 prvalue 。因此在这种情况下,不适用强制省略。
调用loc2 = copy(loc);
时的步骤如下:
a
是从loc
复制构造的。- 函数的返回值是从
a
移动构造的。 loc2
是根据返回值进行移动分配的。
从逻辑上讲,人们可以查看代码并推断出需要完成的操作更少(特别是,当查看copy
时,很明显,从逻辑上讲,来自loc的赋值
到 loc2
就足够了),但编译器不知道代码的目的不是生成副作用(打印输出),并且它没有违反任何规则在这里。
关于c++11 - 按值传递函数中的附加移动构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39633265/