一、左值右值
-
左值:有名字、有内存
-
右值:没名字(临时量)、没内存
-
无法将左值绑定到右值引用
-
无法将右值绑定到左值引用
-
常引用既可以绑定右值,也可以绑定左值
-
一个右值引用变量本身是一个左值
# include <iostream> int main() { int a = 10; int &b = a; // 左值:有名字、有内存;右值:没名字(临时量),没内存 // int &&c = a; // 无法将左值绑定到右值引用 // int &c = 20; // 无法将右值绑定到左值引用 /* 常引用内部实现如下: int temp = 20; const int &c = temp; */ const int &c = 20; // 常引用 /* 内部实现如下: int temp = 20; int &&d = temp; */ int &&d = 20; int &f = d; // 一个右值引用变量本身是一个左值 return 0; }
二、右值拷贝构造函数和右值赋值运算符
下面以手写的CMyString类进行介绍
# include <iostream>
# include <cstring>
class CMyString {
public:
CMyString(const char* str = nullptr)
{
std::cout << "CMyString(const char*)" << std::endl;
if (str)
{
mptr = new char[strlen(str) + 1];
strcpy(mptr, str);
}
else
{
mptr = new char[1];
*mptr = '\0';
}
}
// 左值引用的拷贝构造函数
CMyString(const CMyString& other)
{
std::cout << "CMyString(const CMyString&)" << std::endl;
mptr = new char[strlen(other.mptr) + 1];
strcpy(mptr, other.mptr);
}
// 右值引用的拷贝构造函数
CMyString(CMyString&& other) noexcept
{
std::cout << "CMyString(CMyString&&)" << std::endl;
mptr = other.mptr;
other.mptr = nullptr;
}
// 左值赋值运算符
CMyString& operator=(const CMyString& other)
{
std::cout << "CMyString& operator=(const CMyString&)" << std::endl;
if (this == &other)
return *this;
delete[] mptr;
mptr = new char[strlen(other.mptr) + 1];
strcpy(mptr, other.mptr);
return *this;
}
// 右值赋值运算符
CMyString& operator=(CMyString&& other) noexcept
{
std::cout << "CMyString& operator=(CMyString&&)" << std::endl;
if (this == &other)
return *this;
delete[] mptr;
mptr = other.mptr;
other.mptr = nullptr;
return *this;
}
~CMyString()
{
std::cout << "~CMyString()" << std::endl;
delete[] mptr;
mptr = nullptr;
}
const char* c_str() const
{
return mptr;
}
private:
char* mptr;
};
CMyString getString(CMyString& s)
{
const char* p = s.c_str();
CMyString temp(p);
return temp;
}
int main()
{
CMyString s1("aaaaaaaa");
CMyString s2;
s2 = getString(s1);
std::cout << s2.c_str() << std::endl;
return 0;
}
三、std::move && std::forward
- 模板类型推导
- 引用折叠
- std::move()
- std::forward()
# include <iostream>
// 1、模板函数的类型推演+引用折叠
// & + && -> &
// && + && -> &&
template<typename Ty>
void push_back(Ty &&val) // 右值引用变量本身是一个左值
{
if (full())
expand();
// 2、std::move():得到左值的右值类型
// 3、std::forward():类型的完美转发,能够识别左值还是右值
_allocator.construct(_last, std::forward(val));
_last++;
}
int main()
{
CMyString s1("aaaa");
push_back(s1); // CMyString&
push_back(CMyString("bbbb")); // CMyString&&
return 0;
}