C++ 使用move语义:rvalue引用作为方法参数
我想再次检查一下我对移动语义的理解。我的推理是否遗漏了什么:C++ 使用move语义:rvalue引用作为方法参数,c++,c++11,pass-by-reference,move-semantics,rvalue-reference,C++,C++11,Pass By Reference,Move Semantics,Rvalue Reference,我想再次检查一下我对移动语义的理解。我的推理是否遗漏了什么: #include <iostream> using std::cout; struct A { A() {cout<<"Constructor\n";} ~A() {cout<<"Desctuctor\n";} A(const A&) {cout<<"Copy Constructor\n";} A(A&&) noexcept {
#include <iostream>
using std::cout;
struct A
{
A() {cout<<"Constructor\n";}
~A() {cout<<"Desctuctor\n";}
A(const A&) {cout<<"Copy Constructor\n";}
A(A&&) noexcept {cout<<"Move Constructor\n";}
int x{1};
};
int f1(A a)
{
cout<<"f1(A a)\n";
return a.x;
}
int f2 (A&& a)
{
cout<<"f2 (A&& a)\n";
return a.x;
}
int main()
{
A a1, a2;
f1(std::move(a1));
f2(std::move(a2));
}
从我看到的f2()
,我没有创建任何额外的拷贝,甚至“轻”移动拷贝,这很酷。
所以我现在的理解是,如果我要使用移动语义,我最好总是编写函数/方法签名来接受r值,以避免任何不必要的副本。或者我还遗漏了什么 你几乎总是最好只接受你将按价值保留的输入(除了移动成本非常高的奇数类型) 它保持相同的性能水平(在常见场景中),并使代码非常易于理解。它还非常清楚地表明,您的代码保留了该值(因为它保证会移出),因为右值引用不会强制执行该值
如您所见,删除print语句时,示例的计时和生成的代码是相同的:您缺少一个按值获取其参数的语句。添加,然后再考虑结果。尝试优化而不使用实际代码,使用优化的构建,并实际分析它是一件愚蠢的差事。在构造函数和析构函数中有一个print语句这一事实从根本上改变了生成的二进制文件的构建方式,因为现在它们具有可观察的行为。你根本不了解如何优化代码,你在走错误的学习道路。你的
f1()
和f2()
不是过程函数(非无效),或者将它们定义为void
函数,或者使用返回值,也建议main()
当您将int
作为数据类型返回时,您的代码首先不是安全实现的。具有讽刺意味的是,您缺少了一些#include
sWow,尽管一个调用的是移动构造函数,另一个调用的不是汇编代码是相同的,但这怎么可能呢?@DoehJohn它没有调用移动构造函数-这就是原因。
Constructor
Constructor
Move Constructor
f1(A a)
Desctuctor
f2 (A&& a)
Desctuctor
Desctuctor