0

編集:この同じ質問を (この質問で指摘された問題を修正した後) ここで再質問しました:なぜこの C++0x プログラムが予期しない出力を生成するのですか?

基本的な考え方は、注意しないと、動くものを指すと奇妙な結果になる可能性があるということです。


C++ のムーブ コンストラクターとムーブ代入演算子は、非常にポジティブなもののように思えます。また、複製リソースを指す必要がないため、コピー コンストラクターが意味をなさない状況でも使用できます。

しかし、気をつけないと噛まれてしまうこともあります。これは、コンパイラーが移動コンストラクターのデフォルトの実装を生成できるようにする提案を見てきたため、特に関連性があります。誰かが私にそれを与えることができれば、私はそのようなリンクを提供します。

そのため、完全には明らかではないかもしれないいくつかの欠陥があるコードを次に示します。-std=gnuc++0xコードをテストして、フラグを使用して g++ でコンパイルできることを確認しました。それらの欠陥は何ですか。また、どのように修正しますか?

#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 *);
};
4

1 に答える 1

5

コードには多くの問題があります。

  1. Observer::observed_デフォルトのコンストラクターでは初期化されていないため、デストラクタが呼び出されたときに未定義の動作が発生します。
  2. には 0 以外の値は割り当てられないためObserver::observed_、変数は不要になります。
  3. オブザーバーをオブザーバーに関連付ける方法があったとしても、オブザーバーを移動するときに再登録することはありません。
  4. オブザーバーの移動コンストラクターから値を返そうとしています。
  5. Boost.Signalsは、あなたが解決しようとしている問題をすでに解決しています。
  6. 代入演算子から非 const 参照を返す方が慣用的です。
于 2010-01-24T23:24:29.757 に答える