C++笔记之std::move和右值引用的关系、以及移动语义
code review!
文章目录
- C++笔记之std::move和右值引用的关系、以及移动语义
- 1.一个使用std::move的最简单C++例子
- 2.`std::move` 和 `T&& reference_name = expression;`对比
- 3.右值引用和常规引用的经典对比——移动语义和拷贝语义
- 4.关于 `data = new char[size + 1];`
- 5.std::move的使用场景列举
1.一个使用std::move的最简单C++例子
2.std::move
和 T&& reference_name = expression;
对比
3.右值引用和常规引用的经典对比——移动语义和拷贝语义
右值引用允许我们利用移动构造函数从临时对象中“窃取”资源,避免不必要的拷贝,从而提高效率。而常规引用则会触发拷贝构造函数,产生一个新的对象副本。
代码
#include <iostream>
#include <string>
class MyString {
public:
MyString(const char* str) {
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
std::cout << "Constructor: " << data << std::endl;
}
// 拷贝构造函数
MyString(const MyString& other) {
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
std::cout << "Copy Constructor: " << data << std::endl;
}
// 移动构造函数
MyString(MyString&& other) noexcept {
size = other.size;
data = other.data;
other.size = 0;
other.data = nullptr;
std::cout << "Move Constructor: " << data << std::endl;
}
~MyString() {
delete[] data;
}
void printData() const {
if (data)
std::cout << "Data: " << data << std::endl;
else
std::cout << "Data is empty." << std::endl;
}
private:
size_t size;
char* data;
};
int main() {
MyString str1 = "Hello, World!"; // 调用构造函数
MyString str2 = str1; // 调用拷贝构造函数
MyString str3 = std::move(str1); // 调用移动构造函数
std::cout << "str1: ";
str1.printData(); // 输出空,因为资源已被移动
std::cout << "str2: ";
str2.printData(); // 输出 "Hello, World!"
std::cout << "str3: ";
str3.printData(); // 输出 "Hello, World!"
return 0;
}
4.关于 data = new char[size + 1];
在C++中,使用以null终止的字符串(C风格字符串)时,需要为字符串的内容分配足够的内存来存储字符,同时还需要一个额外的空间来存储字符串的null终止字符(‘\0’),表示字符串的结束。
例如,考虑字符串 “Hello”,它实际上占用了5个字符的内存,即 ‘H’、‘e’、‘l’、‘l’、‘o’,但为了使其成为一个有效的C风格字符串,需要在字符串的末尾添加一个null终止字符 ‘\0’。
因此,为了正确存储以null终止的字符串,我们需要分配的内存大小应该为字符串的长度加上一个额外的字符来存储null终止字符。这就是为什么在 data = new char[size + 1];
语句中,使用了 size + 1
来分配足够的内存以容纳字符串内容和null终止字符。
在C++中,通过这种方式分配内存,并将字符存储在数组中,就可以实现以null终止的字符串表示。这种约定允许我们使用标准的C字符串库函数来操作和处理字符串,例如 strcpy
、strlen
等。