65,187
社区成员




#include<iostream>
using namespace std;
class test
{
public:
test(){c=new char;*c='a';cout<<"构造函数执行...\n";}
~test(){delete c;cout<<"析构函数执行...\n";}
test(const test&r)
{
cout<<"复制构造函数执行...\n";
c=new char;
*c=*(r.c);
}
test(test&&r)
{
cout<<"移动构造函数执行...\n";
c=r.c;
r.c=nullptr;
}
private:
char *c;
};
test f()
{
return test();
}
int main()
{
test b=f();
return 0;
}
struct test
{
test()
{
puts("test::test");
}
test(const test& )
{
puts("test::test(const test& )");
}
test( test&& )
{
puts("test::test(test&&) ");
}
};
test f( test&& v )
{
return std::move(v);
}
test f( const test& v )
{
return v;
}
int main()
{
f( f( f( test() ) ) );
}
一般来说移动构造的代价是小于等于拷贝构造的。
将 test f( test&& v ) 注释就明显看出来效率差距。
比如常用的std::string 效率能提升不小。test f()
{
return test();
}
这种直接返回值优化了,移动语义不是解决这种问题的。
void f( test&& v )
{
//可以调用v的非const成员函数
}
void f( const test& v )
{
//只能调用v的const成员函数
}
很多时候调用const成员函数是不够的
如果调用非const成员函数的话只能再拷贝构造一份对象,而使用移动语义的时候则不需要。
test(const test&r)
{
cout<<"复制构造函数执行...\n";
c=new char;
*c=*(r.c);
}
改成
test(const test&r)
{
cout<<"复制构造函数执行...\n";
c=new char [200000000];
memset(c, 200000000, 0x0);
*c=*r.c;
}
再测试就可以观察到区别(别告诉我说你觉得memset是多余的,实际应用场景中的构造函数里面做的很多都比这个例子的多的多)。
std::string a, b, c;
//....
std::string combine = a + "_" + b + "_" + c; //这里会好几个临时对象
3. 有些对象不时能拷贝的,但是可以move的
比如std::fstream, std::thread
4. move不是在所有场景下都立竿见影.
std::vector<std::vector<std::vector<std::string> > > some_function();
,
use
std::vector<std::vector<std::vector<std::string> > >& some_function(std::vector<std::vector<std::vector<std::string> > >& modify_this_and_return_it);
这个常常意味着表达能力上的损失---代码读起来没有那么美。