左、右值
左值:有地址的值
右值:字面量的值,无地址(临时对象)
static int i = 10;
int& getValue() {
return i;
}
getValue() = 5;
i = 7;
std::cout << i << std::endl;
返回参数带&的方法可接收右值。
void PrintName(std::string&& name) {
std::cout << "r" << name << std::endl;
}
void PrintName(const std::string& name) {
std::cout << "l" << name << std::endl;
}
std::string firstName = "lhx";
std::string lastName = "zxl";
std::string allName = firstName + lastName;
PrintName(firstName + lastName);
PrintName(allName);
&&是接收右值的意思,且在&之前加const也可以使传参接收右值,但是如果重载方法中同样含有&&的话会优先&&。
移动语义
右值是c++11添加的,移动语义必须要右值,移动语义用于将某些对象指针无复制的移动到其他对象指针上来完成对象内容的转换,换句话来说就是浅拷贝。
class String {
public:
String() = default;
String(const char* temp) {
printf("Created!\n");
m_Size = strlen(temp);
m_Data = new char[m_Size];
memcpy(m_Data,temp,m_Size);
}
void Print() {
for (uint32_t i = 0; i < m_Size; i++)
printf("%c",m_Data[i]);
printf("\n");
}
String(const String& temp) {
printf("Copied!\n");
m_Size = temp.m_Size;
m_Data = new char[m_Size];
memcpy(m_Data, temp.m_Data, m_Size);
}
~String() {
printf("destroyed !\n");
delete m_Data;
}
private:
char* m_Data;
uint32_t m_Size;
};
class Entity {
public:
Entity(const String& name) : m_Name(name) {}
void PrintName() {
m_Name.Print();
}
private:
String m_Name;
};
int main() {
Entity entity(String("lhx"));
entity.PrintName();
}
在上述代码中进行了依次copied,发生在构造函数时,将String类型的“lhx”构造复制给String对象。我们现在想通过移动语义来解决这个问题,通过增加右值接收构造函数来对指向“lhx“的指针进行更换,没有进行深拷贝!!!
String(String&& other) noexcept {
printf("Moved!\n");
m_Size = other.m_Size;
m_Data = other.m_Data;
other.m_Size = 0;
other.m_Data = nullptr;
}
String& operator=(String&& temp ) {
printf("Moved!\n");
if (this != &temp) {
delete[] m_Data;
m_Data = temp.m_Data;
m_Size = temp.m_Size;
temp.m_Data = nullptr;
temp.m_Size = 0;
}
return *this;
}//添加在string类中
int main() {
//Entity entity(String("lhx"));
//entity.PrintName();
String string = "hello!";
String dest = std::move(string);
String string = "hello";
String dest = std::move(string);
//将对象转为临时对象
string.Print();
dest.Print();
dest = std::move(string);
dest.operator=(std::move(string));
string.Print();
dest.Print();
std::cin.get();
};
刚才进行的是对右值的移动语义。现在进行对两个有值的对象的移动语义,会使用到std::move函数,它的作用是将一个左值对象转变为一个右值从而避免复制。