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. 从赋值运算符返回非常量引用更为惯用。
于 2010-01-24T23:24:29.757 回答