2013-07-18 65 views
1

編譯我不能讓鐺(蘋果LLVM 4.2版(鐺-425.0.28))編譯這些類:的unique_ptr的類成員和移動語義失敗,鐺

struct A { 
    int f(){return 2;} 
}; 
class Cl{ 
    std::unique_ptr<A> ptr; 

public: 
    Cl(){ptr = std::unique_ptr<A>(new A);} 

    Cl(const Cl& x) : ptr(new A(*x.ptr)) { } 
    Cl(Cl&& x) : ptr(std::move(x.ptr)) { } 
    Cl(std::unique_ptr<A> p) : ptr(std::move(p)) { } 

    void m_ptr(std::unique_ptr<A> p){ 
     ptr = std::unique_ptr<A>(std::move(p)); 
    } 
    double run(){return ptr->f();} 
}; 

我想運行構造函數如下:

std::unique_ptr<A> ptrB (new A); 
Cl C = Cl(ptrB); 

,但如果我這樣做,我得到以下編譯器錯誤: ../src/C++11-2.cpp:66:10:錯誤:調用implicitly- 'std :: unique_ptr'的刪除拷貝構造函數' C.m_ptr(ptrB);

我可以通過運行Cl(std::move(ptrB))解決問題的編譯器,但這實際上並沒有從移動的ptrB的客場所有權:我仍然可以運行ptrB->f()而不會導致運行時崩潰。其次,構造也不是很因爲我想隱藏類接口中的std::move的實現。

在此先感謝。

回答

2

由於的ptrB是按值傳遞到氯的拷貝構造函數,對氯的調用(的ptrB)嘗試創建的ptrB的副本,後者又調用一個(顯然禁用)複製的unique_ptr的構造函數。爲了避免產生的ptrB的額外副本,請執行以下操作:

Cl C = Cl(std::unique_ptr<A>(new A)); //A temporary is created on initialization, no extra copy steps performed 

或者:

std::unique_ptr<A> ptrB (new A); 
Cl C = Cl(std::move(ptrB)); //Move semantics used. Again, no extra copy steps 

或者,使用路過你的拷貝構造函數引用(右值或左值):

class Cl{ 

//... 
public: 
//... 
    Cl(std::unique_ptr<A> &p) : ptr(std::move(p)) { } 

//... 

}; 

std::unique_ptr<A> ptrB (new A); 
Cl C = Cl(ptrB); 

PS哦,順便說一句:對象保持未指定,但有效狀態後,std :: move()。我相信這意味着你仍然可以調用ptrB-> f(),並且保證 返回2 :)

+0

謝謝!通過引用傳遞最適合我,因爲我希望將類Cl的實現保留在接口之外。在我將答案標記爲正確之前,只需要簡單回答一個問題:通過引用構造函數傳遞,是否有任何複製步驟或臨時對象被創建? (我知道你使用移動語義,但它對我來說是新的,所以我仍然要求愚蠢的問題:)) – Plamen

+0

沒有。這是一個經典的傳球 – AlexK

+0

謝謝!它現在完美運行! – Plamen