2016-09-23 72 views
0

最近,我讀了an article關於C++中懶惰的數據結構(這個問題不是關於懶惰,或者特定的數據結構,但它只是動機)。爲什麼不復制一個包含單個shared_ptr的類

懶惰流(名單)實現如下:

template<class T> 
class Stream 
{ 
private: 
    std::shared_ptr <Susp<Cell<T>>> _lazyCell; 
public: 
    Stream() {} 
    Stream(std::function<Cell<T>()> f) 
     : _lazyCell(std::make_shared<Susp<Cell<T>>>(f)) 
    {} 
    Stream(Stream && stm) 
     : _lazyCell(std::move(stm._lazyCell)) 
    {} 
    Stream & operator=(Stream && stm) 
    { 
     _lazyCell = std::move(stm._lazyCell); 
     return *this; 
    } 
    bool isEmpty() const 
    { 
     return !_lazyCell; 
    } 
    T get() const 
    { 
     return _lazyCell->get().val(); 
    } 
    Stream<T> pop_front() const 
    { 
     return _lazyCell->get().pop_front(); 
    } 
}; 

筆者提到的移動構造函數:

我還添加了移動構造函數和效率的移動賦值運算符。

但是,由於明確存在,不能簡單地指定Stream。這背後的動機是什麼?

據我所知,這個類只包含一個shared_ptr,它可以被簡單地複製。在這樣的課堂裏禁止複製建築有什麼好處?

+0

'shared_ptr'不是一般可複製的。 – Barry

+0

不,這聽起來像一個修辭問題:無論如何,獨特的共享目的是什麼? –

+0

@巴里:爲什麼不呢?我認爲這是shared_ptr的全部目的? – choeger

回答

1

shared_ptr在內部用於共享懶惰值單元作爲私有實現的一部分。

但是,從用戶的角度來看,它是一個不可變的對象。提供一個拷貝構造函數和賦值操作符會取消這個不變性。

他正在模擬Haskell的不可變對象的行爲。

如果這樣做是線程安全的,那麼使這個對象可複製是合理的,因爲實際上它是一個(雖然比平常更復雜)共享impl的句柄。

但是,複製者需要了解他們將句柄複製到共享狀態,而不是自己聲明。

+0

所以你說的是,儘管它像一個ref一樣被實現,但它並不意味着被用於這樣的情況。這確實是有見地的。謝謝! – choeger

1

我認爲這是一種過早的優化。

首先,由於三/五(http://en.cppreference.com/w/cpp/language/rule_of_three)的規則,移動複製/分配構造函數將以相同的方式創建,而不必輸入它。

因此唯一的區別是,正如您已經指出的那樣,缺少的複製/分配構造函數。這本來是更好的做法是將它們標記爲刪除,例如:

Stream(Stream & stm) = deleted; 

但這裏真正的問題是使用只有一個所有者共享指針。使用std::unique_ptr會更好。隨着它的使用複製和分配被自動禁用,作者的意圖更清晰。

相關問題