namespace bit { bit::string to_string(int value) { bool flag = true; if (value < 0) { flag = false; value = 0 - value; } bit::string str; while (value > 0) { int x = value % 10; value /= 10; str += ('0' + x); } if (flag == false) { str += '-'; } 引用和移动语义解决上述问题: 在bit::string中增加移动构造,移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不 用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。 std::reverse(str.begin(), str.end()); return str; } }在上面的to_string函数中,实现了将数字转换为字符串的功能
先定义一个空字符串str,然后进行处理后,返回这个str
而返回的这个字符串作为一个局部的临时变量,也是一个将亡值
尽管str在函数内部是一个左值(有名字),但在return的上下文中,C++ 规定它是一个右值,目的是为了调用移动构造函数,避免不必要的深拷贝。
二、右值引用的价值
a. 传统深拷贝问题 (没有移动语义时)
如果bit::string没有移动构造函数,或者在 C++11 以前,return str;会调用深拷贝构造函数:
构造
str:在to_string函数栈上构造局部str,并在堆上为其数据分配空间。return str(深拷贝):调用bit::string的拷贝构造函数,将str的内容深拷贝到返回值位置(例如调用者预留的栈空间)。这涉及:为新对象重新分配堆内存。
将所有字符逐一复制。
销毁
str:局部变量str被销毁,释放其堆内存。
b. 移动构造的优化 (右值引用的价值)
通过将str视为右值,激活了移动构造函数:
构造
str:在to_string函数栈上构造局部str。return str(移动构造):调用bit::string的移动构造函数。这涉及:新对象窃取
str指向的堆内存指针。将
str的内部指针置为nullptr(或空状态)。没有新的堆内存分配和数据复制。
销毁
str:局部变量str被销毁。由于它的内部指针已被置空,它不会释放之前占用的堆内存。
这样,通过将返回值视为右值,效率得到了显著提升,因为它用一个廉价的指针交换操作取代了昂贵的内存分配和深拷贝操作。
三、具体实现
// 移动构造 string(string&& s) :_str(nullptr) ,_size(0) ,_capacity(0) { cout << "string(string&& s) -- 移动语义" << endl; swap(s); } int main() { bit::string ret2 = bit::to_string(-1234); return 0; }再运行上面bit::to_string的两个调用,我们会发现,这里没有调用深拷贝的拷贝构造,而是调用
了移动构造,移动构造中没有新开空间,拷贝数据,所以效率提高了。