2010-01-24 61 views
0

編輯:我再次問同樣的問題在這裏(固定這個問題提出的問題後):Why does this C++0x program generates unexpected output?的C++ 0x移動構造函數疑難雜症

的基本思路是,指向可移動的東西可能淨你如果你不小心,會有一些奇怪的結果。


C++移動構造函數和移動賦值運算符看起來非常積極。它們可以用於複製構造函數沒有意義的情況,因爲它們不需要指向重複的資源。

但有些情況下,他們會咬你,如果你不小心。這是特別相關的,因爲我看到了允許編譯器生成移動構造函數的默認實現的提議。如果有人能給我一個,我會提供一個鏈接。

所以,這裏有一些代碼有一些可能不完全明顯的缺陷。我測試了代碼以確保它在g ++中使用-std=gnuc++0x標誌進行編譯。這些缺陷是什麼,你將如何解決它們?

#if (__cplusplus <= 199711L) && !defined(__GXX_EXPERIMENTAL_CXX0X__) 
    #error This requires c++0x 
#endif 

#include <unordered_set> 
#include <vector> 
#include <utility> 
#include <algorithm> 

class ObserverInterface { 
public: 
    virtual ~ObserverInterface() {} 

    virtual void observedChanged() = 0; 
    virtual void observedGoingAway() = 0; 
}; 

class Observed { 
private: 
    typedef ::std::unordered_set<ObserverInterface *> obcontainer_t; 

public: 
    Observed() {} 
    Observed(const Observed &) = delete; 
    const Observed &operator =(const Observed &b) = delete; 
    // g++ does not currently support defaulting the move constructor. 
    Observed(Observed &&b) : observers_(::std::move(b.observers_)) { } 
    // g++ does not currently support defaulting move assignment. 
    const Observed &operator =(Observed &&b) { 
     observers_ = ::std::move(b.observers_); 
     return *this; 
    } 
    virtual ~Observed() { 
     for (auto i(observers_.begin()); i != observers_.end(); ++i) { 
     (*i)->observedGoingAway(); 
     } 
    } 

    void unObserve(ObserverInterface *v) { 
     auto loc(observers_.find(v)); 
     if (loc != observers_.end()) { 
     observers_.erase(loc); 
     } 
    } 

    void changed() { 
     if (!observers_.empty()) { 
     // Copy observers_ to bector so unObserve works 
     ::std::vector<ObserverInterface *> tmp; 
     tmp.reserve(observers_.size()); 
     tmp.assign(observers_.begin(), observers_.end()); 

     for (auto i(tmp.begin()); i != tmp.end(); ++i) { 
      (*i)->observedChanged(); 
     } 
     } 
    } 

private: 
    obcontainer_t observers_; 
}; 

class Observer : public ObserverInterface { 
public: 
    Observer() {} 
    Observer(const Observer &) = delete; 
    const Observer &operator =(const Observer &b) = delete; 
    // g++ does not currently support defaulting the move constructor. 
    Observer(Observer &&b) : observed_(b.observed_) { 
     b.observed_ = 0; 
     return *this; 
    } 
    // g++ does not currently support defaulting move assignment. 
    const Observer &operator =(Observer &&b) { 
     observed_ = b.observed_; 
     b.observed_ = 0; 
     return *this; 
    } 
    virtual ~Observer() { 
     if (observed_) { 
     observed_->unObserve(this); 
     observed_ = 0; 
     } 
    } 

    virtual void observedChanged() { 
     doStuffWith(observed_); 
    } 
    virtual void observedGoingAway() { 
     observed_ = 0; 
    } 

private: 
    Observed *observed_; 

    // Defined elsewhere 
    void doStuffWith(Observed *); 
}; 
+1

這是一個測驗嗎?你知道缺陷是什麼嗎? – 2010-01-24 22:38:42

+3

沒有「正確的」答案,因爲這需要討論。更好的社區維基它,如果你想這甚至有機會沒有結束...... – Earlz 2010-01-24 22:40:15

+1

@Greg Hewgill,我知道什麼是缺陷。我注意到,有幾個人提問他們知道答案,因爲他們認爲問題的答案對網站有用和有指導意義。這是一個這樣的問題。 – Omnifarious 2010-01-24 22:41:43

回答

5

代碼有很多問題。

  1. Observer::observed_在默認構造函數中未初始化,導致調用析構函數時導致未定義的行爲。
  2. 沒有值,但0被分配給Observer::observed_,使變量變得多餘。
  3. 即使有一種將觀察者與觀察者關聯的方法,移動觀察者時不會重新註冊。
  4. 你試圖從觀察者的移動構造函數中返回一個值。
  5. Boost.Signals已經解決了您正在嘗試解決的任何問題。
  6. 從賦值運算符返回非const引用更通俗。
+0

*嘆*感謝您已經突出了足夠的問題,這些問題與我的想法無關我想我應該刪除這個問題並重新開始。 – Omnifarious 2010-01-24 23:32:29

+0

雖然,你有我想到的其中一個問題。 – Omnifarious 2010-01-24 23:32:59