未调用 Move ctor
我(又)做错了什么吗?
#include <iostream>
using std::cout;
struct Map
{
Map()
{
cout << "Map()\n";
}
Map(const Map& pattern)
{
cout << "Map(const Map& pattern)\n";
}
Map(Map&& tmp)
{
cout << "Map(Map&& tmp)\n";
}
};
Map createMap()
{
return Map();
}
int main(int argc, char* argv[])
{
//dflt
Map m;
//cpy
Map m1(m);
//move
Map m2(Map(m1));//<<I thought that I create here tmp unnamed obj.
Map m3(createMap());//<<---or at least here, but nope...
return 0;
}
请参阅代码中的注释行
编辑[摘自FredOverflow答案]
int main()
{
std::cout << "default\n";
Map m;
std::cout << "\ncopy\n";
Map m1(m);
std::cout << "\nmove\n";
Map m2((Map(m1)));
std::cout << "\nmove\n";
Map m3(createMap());
}
我得到输出:
default
Map()
copy
Map(const Map& pattern)
move
Map(const Map& pattern)//Here why not move ctor aswell as copy?
move
Map()
Map()
Map(Map&& tmp)
Am I doing something wrong (again)?
#include <iostream>
using std::cout;
struct Map
{
Map()
{
cout << "Map()\n";
}
Map(const Map& pattern)
{
cout << "Map(const Map& pattern)\n";
}
Map(Map&& tmp)
{
cout << "Map(Map&& tmp)\n";
}
};
Map createMap()
{
return Map();
}
int main(int argc, char* argv[])
{
//dflt
Map m;
//cpy
Map m1(m);
//move
Map m2(Map(m1));//<<I thought that I create here tmp unnamed obj.
Map m3(createMap());//<<---or at least here, but nope...
return 0;
}
Please see the commented line in the code
Edited [taken from FredOverflow answer]
int main()
{
std::cout << "default\n";
Map m;
std::cout << "\ncopy\n";
Map m1(m);
std::cout << "\nmove\n";
Map m2((Map(m1)));
std::cout << "\nmove\n";
Map m3(createMap());
}
I'm getting output:
default
Map()
copy
Map(const Map& pattern)
move
Map(const Map& pattern)//Here why not move ctor aswell as copy?
move
Map()
Map()
Map(Map&& tmp)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您正在看到回报值优化的实际效果。在 C++ 中,编译器可以优化复制返回的对象,并让函数直接使用存储结果的调用者对象。也不需要调用移动构造函数。
让函数变得更复杂,这样编译器就无法使用优化,你会看到移动的实际情况。例如:
You are seeing return value optimization in action. In C++, the compiler is allowed to optimize away copying returned objects, and let the function work directly with the caller's object where the result is stored. There isn't any need to invoke the move constructor either.
Make the function more complicated, so that the compiler cannot use the optimization, and you'll see moving in action. For example:
您正在声明一个函数,而不是一个对象:
相当于:
可被识别为函数声明。您可以使用额外的括号:
这称为最令人烦恼的解析。
You're declaring a function, not an object:
Is equivalent to:
Which is recognizable as a function declaration. You can use extra parens:
This is called the most vexing parse.
我稍微修改了您的
main
例程以更好地理解输出:这是
g++ -fno-elide-constructors
的输出:正如其他人已经指出的那样,
Map m2(Map(m1));
确实是一个函数声明,因此您不会得到任何输出。第二步不被解释为函数声明,因为createMap
不是类型名称。这里涉及两个移动构造函数。第一个移动将通过评估Map()
创建的临时对象移动到通过评估createMap()
创建的临时对象,第二个移动将m3
从后者。这正是人们所期望的。如果您通过编写
Map m2((Map(m1)));
来修复第一步,输出将变为:同样,这并不奇怪。通过计算
Map(m1)
来调用复制构造函数,然后将该临时对象移动到m2
中。如果您在不使用-fno-elide-constructors
的情况下进行编译,则移动操作会消失,因为它们会被 RVO 或 NRVO 等更高效的优化所取代:我确信 Visual C++ 有一个类似于 < code>-fno-elide-constructors 您可以使用它来更好地理解移动语义。
I slightly modified your
main
routine to understand the output better:And here is the output with
g++ -fno-elide-constructors
:As others already pointed out,
Map m2(Map(m1));
is indeed a function declaration, so you get no output. The second move is not interpreted as a function declaration, becausecreateMap
is not a type name. There are two move constructors involved here. One moves the temporary object created by evaluatingMap()
into the temporary object created by evaluatingcreateMap()
, and the second move initializesm3
from the latter. This is exactly what one would expect.If you fix the first move by writing
Map m2((Map(m1)));
the output becomes:Again, no surprises. The copy constructor is invoked by evaluating
Map(m1)
, and that temporary object is then moved intom2
. If you compile without-fno-elide-constructors
, the move operations disappear, because they are replaced by even more efficient optimizations like RVO or NRVO:I'm sure Visual C++ has a compiler option similar to
-fno-elide-constructors
that you can play with to understand move semantics better.该程序显示了预期的输出。
请注意 createMap() 的更改。它不使用直接的临时值,而是使用命名的返回值。该程序显示了 Visual Studio 2010 上的预期输出。
This program shows expected output.
Note the changes to createMap(). It doesn't employ a direct temporary but a named return value. This program shows the intended output on Visual Studio 2010.
我认为编译器会对上述内容进行 RVO (返回值优化),因此不会创建任何临时对象。
如果将其更改为以下内容,您应该会看到您的移动向量被调用。
I would think that the compiler would've done an RVO (return value optimization) on the above, thus no temporaries would ever be created.
If you change it to the following, you should see your move ctor getting invoked.