C ++ 0x移动构造函数陷阱[关闭]

Posted

技术标签:

【中文标题】C ++ 0x移动构造函数陷阱[关闭]【英文标题】:C++0x move constructor gotcha [closed] 【发布时间】:2010-01-24 22:34:56 【问题描述】:

编辑:我在这里重新问了同样的问题(在解决了这个问题指出的问题之后):Why does this C++0x program generates unexpected output?

基本的想法是,如果你不小心,指向可移动的东西可能会给你带来一些奇怪的结果。


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 *);
;

【问题讨论】:

这是一个测验吗?你知道缺点是什么吗? 没有“正确”答案,因为这需要讨论。如果您希望它甚至有机会不被关闭,请使用更好的社区 Wiki.... @Greg Hewgill,我知道缺陷是什么。我注意到有几个人提出了他们知道答案的问题,因为他们认为这些问题的答案在网站上会很有用和有启发性。这是一个这样的问题。 @Omnifarious:对于这样的“我知道答案,你呢?”一种有用的问题,它必须足够具体,以至于可以从中学习的人实际上会找到它。目前它对此过于开放。如果您想为其他人尚未提出的问题提供答案,那么请让问题具体到想要的人会找到它。 @jalf,这是有道理的。我投票结束了这个问题,我会修改它并以不同的方式提问。 【参考方案1】:

代码有很多问题。

    Observer::observed_ 在默认构造函数中未初始化,导致调用析构函数时出现未定义的行为。 除了 0 之外没有任何值被分配给 Observer::observed_,因此变量是多余的。 即使有办法将观察者与被观察者相关联,移动观察者时也不会重新注册。 您正试图从观察者的移动构造函数返回一个值。 Boost.Signals 已经解决了您要解决的任何问题。 从赋值运算符返回非常量引用更为惯用。

【讨论】:

叹息 谢谢。您已经强调了足够多与我的想法无关的问题,我认为我应该删除问题并重新开始。 不过,您遇到了我正在考虑的问题之一。 #3.

以上是关于C ++ 0x移动构造函数陷阱[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中显式删除移动构造函数的用例 [关闭]

在 C++0x 中继承构造函数

VC2010 中的 C++0x 对等构造函数

在 C++0x 中,非静态数据成员初始化器会覆盖隐式复制构造函数吗?

C++5大构造函数

C ++派生类构造函数[关闭]