2010-06-23 119 views
3

如果我有返回,我沒有控制其源的類的實例的引用的函數,說list<int>防止返回值參考的拷貝構造和賦值

list<int>& f(); 

我要確保它的值是分配給另一個參考,例如:

list<int> &a_list = f(); 

如果用戶是不是要做到:

list<int> a_list = f(); // note: no '&', so the list is copied 

我希望它成爲編譯時錯誤,因爲用戶只會操作列表的副本而不是原始列表(這絕不是我的應用程序的預期/想要的)。

有沒有什麼辦法可以防止上述的複製構造和賦值(比如說通過某種「包裝」類)?

理想情況下,如果要使用某些包裝類,比如wrapper<T>,我希望它適用於任何類型的對象T


是的,我知道,對於一個類,我可以控制,我可以簡單地拷貝構造函數和賦值操作符private,如:

class MyClass { 
public: 
    // ... 
private: 
    MyClass(MyClass const&); 
    MyClass operator=(MyClass const&); 
}; 

禁止拷貝建設和任務;但是,如上所示,我想這樣做,例如,std::list我不能簡單地複製構造函數和賦值運算符private

+1

@GMan:當然這是微不足道的,因爲它是1個字符的錯誤;然而,忘記輸入'&'很容易。如果您仍然看不到這一點,那麼只需忽略問題並繼續。 – 2010-06-23 23:34:33

+0

請注意,如果我問你爲什麼要這樣做? – fingerprint211b 2010-06-23 23:52:59

+0

@Paul:但是這就像是說當你需要'x + = 1'時,你需要一種防止'x + 1'的方法。這是「讓我試着拯救你」的道路上的許多痛苦,而不是「你需要理解引用」。 – GManNickG 2010-06-24 00:04:39

回答

1

那麼,你可以用一個包裝。爲重載的列表製作一個包裝 - >但從來沒有爲您提供對真實參考的訪問。我想可能有辦法解決這種方法,但它必須是有意的。應該足以通知客戶他們真的不應該這樣做。

+0

如果用戶必須使用operator->,那麼他/她不能簡單地寫出正確的表單,如上所示。 – 2010-06-24 00:00:57

+0

@Paul:他們可以(也可以)在任何地方做'列表',他們可以刪除那個引用。您必須更改語法或保留原始「問題」。 – GManNickG 2010-06-24 00:23:27

+0

「正確的形式」?跆拳道是應該是什麼意思?如果你堅持一個不可能的答案,那麼恐怕你被困在神的乞求之下來改變宇宙。我試圖爲您提供一些解決您嘗試解決的問題的方法。如果那還不夠好......那麼祝你好運。 – 2010-06-24 04:58:20

1

您可以繼承此類,並創建一個匹配的構造函數來調用父類的構造函數(例如,具有相同的數據構造函數,只將數據傳遞給父類),並將複製構造函數並複製私人分配。或者,你可以從boost :: noncopyable和那個類中派生出來。然後您可以安全地使用指向基類的指針/引用。

編輯:如果該類有一個接口,您可以使一個裝飾器實現該接口,這是不可複製的,並沒有提供一種方法來獲取它包裝的對象的引用/指針。

如果這些都不是一個選項,您可以編寫一個具有相同確切方法的類,並且看起來相同,不需要複製構造函數和複製分配,這會調用您正在守衛的類的適當方法(再次,裝飾者,困難的方式)。但我會避免這種情況。

+0

根據我上面添加的文本,從某些任意類T繼承並且具有匹配的構造函數是不可能的。 – 2010-06-23 23:59:55

+0

你將能夠用這種方法完成的最好的事情是使用默認構造函數捕獲所有內容。但鑑於您的其他要求,這可能是您的最佳選擇。 – pkh 2010-06-24 00:22:25

+0

@pkh:我不明白你的意思是「用默認構造函數捕獲所有東西」。也許你可以寫一些代碼(?)。 – 2010-06-24 00:36:02

1

我不相信有什麼語言可以讓你這樣做。可以說,你可以返回一個指針,以便他們必須採取明確的行動來複制它。

OTOH,這裏有一個你可以使用的包裝的例子。請注意,Uncopyable通過值返回,而不是引用。 (但沒關係,因爲它可能只是指針大小。)

#include <iostream> 
#include <list> 

template <typename T> 
class Uncopyable 
{ 
public: 
    Uncopyable(T& r) : ref(r) {} 

    T* operator->() { return &ref; } 

private: 
    T& ref; 
}; 

Uncopyable<std::list<int> > get_list() 
{ 
    static std::list<int> l; 
    l.push_back(l.size()); 
    return l; 
} 

int main() 
{ 
    for (int i = 0; i < 10; ++i) 
    { 
     Uncopyable<std::list<int> > my_l = get_list(); 
     std::cout << my_l->size() << std::endl; 
    } 
} 
+0

問題在於用戶必須瞭解Uncopyable並在代碼中使用它。理想情況下,我希望解決方案是透明的。 – 2010-06-24 00:04:39

+2

然後你骨架。 – pkh 2010-06-24 00:20:12

+0

那就是如果答案本身。我只是想確保沒有聰明的方式去做我想做的事。 – 2010-06-24 00:28:43

2

這是從我以前的一個單獨的答案,因爲問題已澄清。我以前的回答可能對有理智要求的人有用,所以我保持完好無損。

期望的行爲是不可能:要求是要能一般回報的東西,看起來酷似一個T&但是,這並不像一個T。事實上,這個返回的東西實際上並不是一個引用,必須以某種方式讓用戶(和編譯器!)知道。

1

我覺得這是一個奇怪的要求。複製列表或使用它作爲參考的策略應該由用戶來正常使用,但如果出於某種原因,複製列表永遠不會正確,那麼封裝類就會訣竅。

如果用戶知道他在做什麼,他應該理解使用列表的深層副本工作的區別,而不是使用淺拷貝和修改原件。如果用戶不理解這一點,他還沒有使用C++的業務。

[編輯]我剛纔注意到有人發佈了一個幾乎相同的解決方案。 類可以非常簡單:

template <class T> 
class NoncopyablePtr 
{ 
private: 
    T* ptr; 

public: 
    /*implicit*/ NoncopyablePtr(T* iptr): ptr(iptr) {} 

    T* operator->() const 
    { 
     return ptr; 
    } 
}; 

這將使用戶複製指針對象是非常艱難的。他們必須調用operator->明確地解除結果。現在簡單地返回NoncopyablePtr < std :: list < int>>然後你會在客戶端(儘管不是不可能)製作該列表的副本非常困難。

如果你不喜歡使用operator->那麼恐怕真的沒有其他方法來阻止用戶輕鬆地複製結果。

相關問題