C++11右值引用實際使用示例
阿新 • • 發佈:2019-01-08
class CXyString { /* 用於交換物件內容 */ friend void swapObj(CXyString & o1, CXyString & o2); //也可以直接在這裡實現這個函式 private: char * m_buff; size_t m_cap; size_t m_size; public: /* 0 無參建構函式 */ CXyString() : m_buff(nullptr), m_size(0), m_cap(0) { printf("[CREATE EMPTY] %p.\n", this); } /* 1 建構函式 */ CXyString(const char * str, size_t len = 0) : CXyString() { printf("created, set data\n"); if (str) append(str, len); } /* 2 左值引用建構函式,這裡不可以寫成傳值型別的引數,會導致呼叫過載不明確 */ CXyString(const CXyString & o) : CXyString(o.data(), o.size()) { printf("deep copy completed!!!\n"); } /* 3 右值引用建構函式 */ CXyString(CXyString && o) : CXyString() //一定要呼叫無參建構函式以清空成員變數,不然交換完之後釋放右值時會導致釋放m_buff所指向的無效地址(vs中debug狀態下為0xcccccccc) { printf("created, move data.\n"); swapObj(*this, o); //交換資料內容 } /* 左值版本的賦值 */ CXyString & operator=(const CXyString & o) //值傳遞,以達到傳參前自動呼叫複製建構函式的目的 { printf("entered operator=\n"); if (&o == this) return *this; CXyString tmp(o); //複製一個新的,再交換。因為左值引用引數不能影響引數原來的內容 swapObj(*this, tmp); printf("leaving operator=\n"); return *this; } /* 右值版本的賦值 */ CXyString & operator=(CXyString && o) { printf("entered operator=&&\n"); if (&o == this) return *this; swapObj(*this, o); //直接交換,右值引數是可以修改的,因為沒有任何人能引用到傳進來的右值引數(其實是個臨時變數,用完即棄的那種) printf("leaving operator=&&\n"); return *this; } /* 連線字串,傳入記憶體地址 */ CXyString operator+(const char * str) { printf("entered operator+\n"); //if (str == nullptr) // return CXyString(*this); // return std::move(CXyString(*this)); //會被RVO,vs中測試直接return的可以不move,不會再複製一份 CXyString & ret = CXyString(*this); //ret可以是引用也可以為非引用,即使為非引用也不會再複製一份給ret ret.append(str); printf("leaving operator+\n"); //避免深複製,std::move返回&&右值引用,接著return會呼叫本類的右值引用版建構函式來轉移m_buff中的資料而非複製。因為ret引數在本函式結束時會被釋放 return std::move(ret); } /* 連線字串,傳入物件 */ CXyString operator+(const CXyString & o) { return operator+(o.data()); } /* 析構 */ virtual ~CXyString() { printf("[DELETE] %p!\n", this); clear(); } const char * data() const { return m_buff; } const char * c_str() const { return m_buff; } size_t size() const { return m_size; } size_t length() const { return m_size; } size_t cap() const { return m_cap; } bool empty() const { return m_size == 0; } void clear() { if (m_buff) { delete m_buff; m_buff = nullptr; m_size = 0; } } void reserve(size_t n) { if (n + 1 <= m_cap) return; char * tmpBuff = new char[n + 1]; tmpBuff[0] = '\0'; if (m_size > 0) { memcpy(tmpBuff, m_buff, m_size <= n ? m_size : n); tmpBuff[n] = '\0'; delete m_buff; } m_buff = tmpBuff; m_cap = n + 1; } void append(const char * str, size_t n = 0) { if (n == 0) n = strlen(str); if (n == 0) return; if (m_cap < m_size + n + 1) { reserve(m_size + n + 1); } memcpy(m_buff + m_size, str, n); m_buff[m_size + n] = '\0'; m_size += n; } void append(const CXyString & o) { append(o.data(), o.size()); } }; /* 用於交換物件內容 */ static void swapObj(CXyString & o1, CXyString & o2) //類外friend函式,也可以在類內直接實現 { std::swap(o1.m_buff, o2.m_buff); //std::swap用一來交換兩個變數 std::swap(o1.m_cap, o2.m_cap); std::swap(o1.m_size, o2.m_size); }