c++ 拷貝控制需要注意的幾點

  1. 十三章 拷貝控制

  • 類的默認合成拷貝構造函數會拷貝數組成員。

  • 拷貝構造的發生條件及優化

    1. 實參傳遞給非引用類型形參

      class A(B)
      
    2. 函數返回類型爲非引用類型並返回一個對象。 注意編譯器可能會使用ROV(Return Value Optimization)優化,導致並沒有發生拷貝構造.

      1. 返回值優化(RVO),即通過將返回值所佔空間的分配地點從被調用端轉移至調用端的手段來避免拷貝操作。返回值優化包括具名返回值優化(NRVO)與無名返回值優化(URVO),兩者的區別在於返回值是具名的局部變量還是無名的臨時對象

      2. RVO發生的條件:

        1. return 的值類型與 函數聲明的返回值類型相同
        2. return的是一個局部對象
        // g++ 默認執行NRVO與URVO優化,vs不確定
        class B 
        {
        	public:
        		B(int p){
        			cout << "in Direct init "  << endl;
        			a = p;	
        		}
        		B(const B& rp){
        			cout << "in copy init" << endl;
        			a = 5;
        		}
        		B& operator= (const B& ep){
        			cout << "in operator= init " << endl;
        			a = 6;
        			return *this;
        		}
        	int a ;
        };
        B RetB1()
        {
            return B(1);//無名臨時對象
        }
        B RetB2()
        {
            B b(2);
            return b;//named局部對象
        }
        int main()
        {
            B b1 = RetB1();// URVO優化,未發生拷貝
            B b2 = RetB2();// NRVO優化,未發生拷貝  
        }
        
    3. 類對象使用=初始化時。

      B b(2);
      B b1 = b;// 拷貝構造
      

      ​ 注意若右值是臨時變量導致 右值拷貝優化

      1. 右值拷貝優化:即當類類型的臨時對象=初始化同類型的對象時,通過直接利用該臨時對象的方法來避免拷貝操作。
        這項優化只能用於右值(臨時對象),不能用於左值

        int main
        {
        	B a(9);
        	B b1 = 8;// 8初始化的臨時對象,直接作爲b1.
        	cout << " b1.a = " << b1.a<< endl;
        	b1 = 9; // 因爲右值是B(9)臨時變量,=重載函數的引用必須是const的
        	cout << " b1.a = " << b1.a<< endl;
        
        	getchar();
        
        	return 0;
        }
        
    4. 花括號列表初始化元素爲類類型的數組。

    5. 因爲以上條件下都可能發生隱士初始化,所以一般不對拷貝初始化做explicit
      
  • 標準庫要求保存在容器中的類型都要有拷貝賦值運算符 T& operator=(const T& ),否則會使用默認的合成拷貝賦值運算符。

  • 類內成員默認初始化在構造函數體之前完成,默認析構在析構函數體之後開始。

  • 類默認構造(包括拷貝)無法完成對const或引用成員的初始化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章