移動語義的例子
#include<iostream>
#include<vector>
using namespace std;
#define pfunc \
cout << __FUNCTION__<<":"<<__LINE__ << endl;
class MyString
{
public:
MyString() :m_data(nullptr), m_len(0)
{
pfunc;
}
MyString(const char* pstr)
{
pfunc;
m_len = strlen(pstr);
copy_data(pstr);
}
//拷貝構造
MyString(const MyString& other)
{
pfunc;
if (other.m_data)
{
m_len = other.m_len;
release_data();
copy_data(other.m_data);
}
}
//賦值構造
MyString& operator=(const MyString& other)
{
pfunc;
if (this != &other)
{
m_len = other.m_len;
release_data();
copy_data(other.m_data);
}
return *this;
}
// 移動拷貝構造, 偷other的資源
MyString(MyString&& other)
{
pfunc;
m_len = other.m_len;
m_data = other.m_data;
other.m_data = nullptr;
}
// 移動賦值構造
MyString operator+(MyString& other)
{
pfunc;
MyString temp;
temp.m_len = other.m_len + this->m_len;
temp.m_data = new char[temp.m_len + 1];
memcpy(temp.m_data, this->m_data, this->m_len);
memcpy(temp.m_data+this->m_len, other.m_data, other.m_len);
temp.m_data[temp.m_len] = 0;
return temp;
}
~MyString()
{
release_data();
}
private:
void copy_data(const char* pdata)
{
if (pdata)
{
m_data = new char[m_len + 1];
memcpy(m_data, pdata, m_len);
m_data[m_len] = 0;
}
}
void release_data()
{
if (m_data)
{
delete m_data;
m_data = nullptr;
}
}
private:
char* m_data = nullptr;
size_t m_len = 0;
};
MyString test()
{
MyString t("test");
return t;
}
int main()
{
MyString s1 = "Hello World";
MyString s2(s1);
MyString s3 = move(s1);// call move constructor
MyString s11 = " Good Morning";
MyString s4 = s2 + s11;// call move constructor
MyString s5(std::forward<MyString>(s3));// call move constructor
return 0;
}
2 move函數
把左值當成右值使用,比如swap函數
template<class _Ty,
class> inline
void swap(_Ty& _Left, _Ty& _Right)
_NOEXCEPT_COND(is_nothrow_move_constructible_v<_Ty>
&& is_nothrow_move_assignable_v<_Ty>)
{ // exchange values stored at _Left and _Right
_Ty _Tmp = _STD move(_Left);
_Left = _STD move(_Right);
_Right = _STD move(_Tmp);
}
- forward函數
forward函數如上面的例子,也可以把左值當成右值使用。
但它不僅僅是這樣。通過它可以實現完美轉發,完美轉發就是一個函數將參數繼續轉交給另一個函數進行處理,原參數可能是右值,可能是左值,如果還能繼續保持參數的原有特徵,就是完美。
其實,forward可以替代move,不過最佳實踐告訴我們,右值引用使用move,萬能引用使用forward
template<typename T>
void print(T& t) {
cout << "left value" << endl;
}
template<typename T>
void print(T&& t) {
cout << "right value" << endl;
}
template<typename T>
void MyForward(T && v) {
print(std::forward<T>(v));
}
int main() {
int x = 404;
MyForward(11);
MyForward(x);
return 0;
}