程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> c++ 11學習筆記--右值引用和移動構造語義

c++ 11學習筆記--右值引用和移動構造語義

編輯:C++入門知識

c++ 11學習筆記--右值引用和移動構造語義


今天我決定嘗試用另外一種方式來表達,任何新語法的的產生都是為了解決某個問題,所以今天先看問題。   復制代碼 class myStr { protected:     char* str_;      public:     myStr(void)                       // 默認的構造函數,什麼也不做     : str_(nullptr)     {}          myStr(const char* rhs)            // 普通賦值構造函數     : str_(nullptr)     {         if (!rhs) return;         str_ = new char[1024];         strcpy(str_, rhs);       //  cout << "Str constructor " << str_ << std::endl;     }          myStr(const myStr& rhs)             // 拷貝構造函數     : str_(nullptr)     {         if (!rhs) return;         str_ = new char[1024];         strcpy(str_, rhs.str_);       //  cout << "Str copy constructor " << str_ << std::endl;     }          myStr(myStr&& rhs)     : str_(nullptr)     {         swap(rhs);       //  std::cout << "Str move constructor " << str_ << std::endl;     }          ~myStr()                          // 析構函數     {         if (!str_) return;       //  std::cout << "Str destructor " << str_ << std::endl;         delete [] str_;     }          const myStr& operator=(myStr rhs)   // 賦值操作符重載     {         rhs.swap(*this);            // 使用copy-and-swap慣用法獲得數據         return (*this);             // 避免重復撰寫operator=     }          void swap(myStr& rhs)             // 交換算法     {         std::swap(str_, rhs.str_);     }          operator char*(void) const     {         return str_;     }          myStr& operator+=(const char* rhs)     {         if (rhs) strcat(str_, rhs);         return (*this);     }      //    friend myStr operator+(const myStr& x, const myStr& y) //    { //        return myStr(x) += y; //    }     friend myStr operator+(const myStr& x, const myStr& y)     {         return std::move(myStr(x) += y); } 復制代碼 執行下面的代碼   復制代碼 myStr ss("000");     myStr s1("11111"), s2("22222"), s3("3333333"), s4("4444444");     cout << std::endl;     time_t timestamp1;     time_t timestamp2;     time_t timestamp3;          const long long max = 30000000;     time(&timestamp1);       for (long long i = 0; i<max; i++) {         ss = s1 + s2 + s3 + s4;     }      time(&timestamp2);       timestamp3 = timestamp2 - timestamp1; 復制代碼  下面的代碼是唯一不同的實現,但是卻帶來30-40%的性能差距。   復制代碼 /    friend myStr operator+(const myStr& x, const myStr& y) //    { //        return myStr(x) += y; //    }     friend myStr operator+(const myStr& x, const myStr& y)     {         return std::move(myStr(x) += y); } 復制代碼 再找一個例子   復制代碼 class MemoryBlock { public:          // 構造器(初始化資源)     explicit MemoryBlock(size_t length)     : _length(length)     , _data(new int[length])     {         std::cout << "MemoryBlock constructor "  << std::endl;     }          // 析構器(釋放資源)     ~MemoryBlock()     {         if (_data != nullptr)         {             delete[] _data;         }         std::cout << "MemoryBlock destructor "  << std::endl;     }          // 拷貝構造器(實現拷貝語義:拷貝that)     MemoryBlock(const MemoryBlock& that)     // 拷貝that對象所擁有的資源     : _length(that._length)     , _data(new int[that._length])     {         std::copy(that._data, that._data + _length, _data);         std::cout << "copy constructor "  << std::endl;     }          // 拷貝賦值運算符(實現拷貝語義:釋放this + 拷貝that)     MemoryBlock& operator=(const MemoryBlock& that)     {         if (this != &that)         {             // 釋放自身的資源             delete[] _data;                          // 拷貝that對象所擁有的資源             _length = that._length;             _data = new int[_length];             std::copy(that._data, that._data + _length, _data);         }         return *this;     }          // 移動構造器(實現移動語義:移動that)     MemoryBlock(MemoryBlock&& that)     // 將自身的資源指針指向that對象所擁有的資源     : _length(that._length)     , _data(that._data)     {         // 將that對象原本指向該資源的指針設為空值         that._data = nullptr;         that._length = 0;     }          // 移動賦值運算符(實現移動語義:釋放this + 移動that)     MemoryBlock& operator=(MemoryBlock&& that)     {         if (this != &that)         {             // 釋放自身的資源             delete[] _data;                          // 將自身的資源指針指向that對象所擁有的資源             _data = that._data;             _length = that._length;                          // 將that對象原本指向該資源的指針設為空值             that._data = nullptr;             that._length = 0;         }         return *this;     } private:     size_t _length; // 資源的長度     int* _data; // 指向資源的指針,代表資源本身 };   MemoryBlock f() { return MemoryBlock(50); } 復制代碼 執行下面的代碼   復制代碼 const long long max = 100000;     time_t timestamp1;     time_t timestamp2;     time_t timestamp3;       time(&timestamp1);     for (long long i = 0; i<max; i++)     {         MemoryBlock a = MemoryBlock(50);           MemoryBlock c = std::move(a);     }          time(&timestamp2); timestamp3 = timestamp2 - timestamp1; 復制代碼 如果把MemoryBlock c = std::move(a)換成MemoryBlock c = a;   性能上大概也有30%的差距。       這就是右值引用和移動構造語義帶來的好處,我理解就是以前只能引用左值,而右值是不能引用的,新語法的加入實現了右值的引用,減少了零時對象的產生銷毀,但是也帶來了更多怪異的語法,明顯增加了c++的學習成本,如果語法設計角度,像oc一樣增加類似引用計數器來管理對象,會不會更加優雅一下,至少讓上層的碼農不會那麼累,其實通智能指針也能達到同樣的效果。       這麼多年了c++都在做加法,讓學習,使用成本太高了,標准委員為的大爺些什麼時候考慮一下做點減法呢,不要讓c++那麼學院派或者滿地都是陷阱,也不要讓實現一種技術有10種方法,但是有5種都是陷阱。靠!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved