2011-05-16 46 views
0

我有一個Visual Studio 2008 C + +項目與管理資源,無法複製的類。我已經實現了參考轉換結構語義(ala std::auto_ptr)。傳輸對象的所有權與安置新

class Test; 

struct Test_Ref 
{ 
    Test& ref_; 
    Test_Ref(Test& t) : ref_(t) { }; 
private: 
    Test_Ref& operator=(Test_Ref const&); 
}; // struct Test_Ref 

class Test 
{ 
public: 
    explicit Test(int f = 0) : foo_(f) { }; 

    Test(Test& other) : foo_(other.Detach()) { }; 

    Test& operator=(Test& other) 
    { 
     foo_ = other.Detach(); 
     return *this; 
    }; 

    Test(Test_Ref other) : foo_(other.ref_.Detach()) { }; 

    Test& operator=(Test_Ref other) 
    { 
     foo_ = other.ref_.Detach(); 
     return *this; 
    }; 

    operator Test_Ref() { return Test_Ref(*this); }; 

private: 

    int Detach() 
    { 
     int tmp = foo_; 
     foo_ = 0; 
     return tmp; 
    }; 

    // resource that cannot be copied. 
    int foo_; 
}; // class Test 

不幸的是,當我使用這個模式與使用投放新的圖書館,我得到一個編譯錯誤:

.\test.cpp(58) : error C2558: class 'Test' : no copy constructor available or copy constructor is declared 'explicit' 
    .\test.cpp(68) : see reference to function template instantiation 'void Copy<Test>(T *,const T &)' being compiled 
    with 
    [ 
     T=Test 
    ] 

例如:

template< class T > inline void Copy(T* p, const T& val) 
{ 
    new(p) T(val); 
} 

int _tmain(int /*argc*/, _TCHAR* /*argv*/[]) 
{ 
    Test* __p = new Test(); 
    Test __val; 
    Copy(__p, __val); 
    return 0; 
} 

如何修改Test這樣它可以與新的放置一起使用並仍保留其所有權語義?

感謝, PaulH

+0

避免使用雙下劃線開頭的名稱,因爲這些名稱是爲實現(編譯器+標準庫)保留的名稱。另外,從'Test * p = NULL;'到'Test * p = new Test();'的變化並不能解決未定義的行爲,它只是將它換成另一個(這是UB構造同一個對象兩次,你正在分配內存並在'main'中調用構造函數的代碼,然後在'Copy'中再次調用構造函數(並且永不破壞或釋放內存......) – 2011-05-16 22:33:34

回答

1

關注main函數,因爲這應該表明你想要的語義,有兩個大問題:首先,你沒有分配內存,這意味着如果編譯器會處理代碼,它會導致UB(會嘗試調用Test構造了在放置新的操作NULL地址

的另一個問題是衆所周知的std::auto_ptr用戶:拷貝構造函數的簽名需要一個非const引用,這意味着,你不能在一個const對象上調用它;另一方面,你試圖調用Copy模板中的拷貝構造函數承諾不改變第二個參數引用的對象:

template <typename T> 
void Copy(T* p, T& o) { 
    new (p) T(o);   // would work, object is non-const 
} 

最後,我不知道,如果是由於複製到這個問題,但我不知道你的意圖是與參照包裝類什麼,你在開始時提供,所以你可能想澄清。

+0

呃,我很專注於奇怪而神祕的放置 - 新的,我完全錯過了它上面巨大的閃爍'const'。 。 – PaulH 2011-05-17 00:52:03

0

您的問題無關,與放置新的。在void Copy中,您試圖複製Test類型的對象,但不允許複製。那就是問題所在。此外,您試圖在NULL上放置新的。您無法正確實施該結構,因爲這個常量 - operator test_ref()永遠不會被調用,因爲您使用了const T&並且它是非常量運算符。這意味着,除非你想讓他們認爲它應該是複製品而讓他們感到驚訝,否則你不能這樣做。

+0

修復NULL上的放置位置 – PaulH 2011-05-16 22:27:29

+0

是的,這個目標對象是在指定副本時執行移動,類似於'std :: auto_ptr'。 – PaulH 2011-05-16 22:28:27