C语言中如何移动语义为?
摘要:移动语义 移动语义让事情变得简单,移动语义本质上允许我们移动对象。这在C++11之前是不可能的,因为C++11引入了右值引用,这是移动语义所必须的。基本思想是,当我们写
移动语义
移动语义让事情变得简单,移动语义本质上允许我们移动对象。这在C++11之前是不可能的,因为C++11引入了右值引用,这是移动语义所必须的。基本思想是,当我们写C++代码时,有很多情况下,我们不需要或者不想把一个对象从一个地方复制到另一个地方,但又不得不复制,因为这是唯一可以复制的地方。
例如:
我们把一个对象传递给一个函数,那么它要获得那个对象的所有权,我没有选择,只能拷贝。
当我想从函数返回一个对象时也是一样,我仍然需要在函数中创建那个对象,然后返回它,也就是说又需要复制对象。
现在我不喜欢用返回值作为例子,因为因为有一种叫做返回值优化的东西对这部分进行了优化,让它不再是个问题。但是在第一个例子中,如果我需要传入一个对象,这个对象放入某个函数,而这个函数需要得到这个对象的所有权或者其它,我仍然需要在当前堆栈中构造一个一次性对象,不管它在哪里,然后将它复制到我正在调用的函数中,而这并不理想。因为我在这里不需要它,而是在那里需要,但我又不能在那里构造它,因为我需要先在这里构造它,然后把它传递进去,它变得一团糟。
当然,如果你的对象只是由一对整数或类似的东西组成,那复制也没什么大不了的,但如果你的对象需要堆分配内存之类的(比如:一个字符串,如果你需要复制它,你需要创建一个全新的堆空间),这就不好了,这会成为一个沉重的复制对象,这正是移动语义的用武之地。
如果我们只是移动对象,而不是复制它,那么性能会更高。可以类比剪切和复制的区别。
#include<iostream>
#include<string>
//1. 自定义一个被操作的类
class String {
private:
uint32_t m_Size;
char* m_Data;
public:
String() = default;
String(const char* string) {
printf("Created!\n");
m_Size = strlen(string);
m_Data = new char[m_Size];
memcpy(m_Data, string, m_Size);
}
//拷贝构造函数
String(const String& other) {
printf("Copied!\n");
m_Size = other.m_Size;
m_Data = new char[m_Size];
memcpy(m_Data, other.m_Data, m_Size);
}
//move构造函数,只接收一个右值,意思是一个临时值
//noexcept: 它不应该抛出异常,并不是经常使用它,但是为了保证绝对正确,我们会这样做
//通过指定这个构造函数,希望最终当我们执行这个“复制”构造函数时,不会复制。而是变成 移动了
String(String&& other) noexcept {
printf("Moved!\n");
m_Size = other.m_Size;
//这里不再复制,而是重新指向参数传过来的数据地址,所以没有复制
m_Data = other.m_Data;
//但是这个是移动复制构造函数,所以有2个String实例,而第二个的实际数据指针也指向第一个的数据地址。
