在“观察者模式”上复制构造函数

时间:2019-10-03 16:03:16

标签: c++

假设我们的设计模式与此类似:

#include <set>

class Receiver;

class Transmitter {
public:
   Transmitter() = default;

   virtual ~Transmitter() { 
      for(auto recv : m_receivers){
         recv->setSource(nullptr);
      }
   }

   const std::set<Receiver*> getReceivers(){
      return m_receivers;
   }
private:
   std::set<Receiver*> m_receivers;
};

class Receiver {
public:
   Receiver() = default;
   Receiver(const Receiver& other){
      setTransmitter(other.m_trans);
   }
   ~virtual ~Receiver(){
      setTransmitter(nullptr);
   }

   void setTransmitter(Transmitter* tr){
      if(m_trans) m_trans->m_recv.erase(this)
      m_trans=tr;
      if(m_trans) m_trans->m_recv.insert(this)
   }
private:
   Transmitter* m_trans = nullptr;
};

这似乎是Observer pattern:两个类之间的关系为1:M,并且两者相互引用。

现在想象我们要使它们与std::vector或任何其他类似的std容器兼容。因此,它必须是可复制构造的(或可移动的)。

Receiver可以复制(如上面的代码所示),但是,发送器会出现问题。我曾考虑过其他选择,但我无法决定该怎么做:

  • 复制构造函数应充当默认构造函数还是应将其删除?
  • 我应该定义一个移动构造函数来窃取其他接收器吗?
  • 还是应该简单地禁止复制和移动初始化? (无法解决问题)

    有一个similar question in stack overflow about this problem in Java。但是对于C ++,答案可能会改变

1 个答案:

答案 0 :(得分:3)

移动构造函数将是合适的:

Transmitter(Transmitter&& other) noexcept : m_receivers(std::move(other.m_receivers)) {
   for (auto recv : m_receivers) {
       recv->m_trans = this;
   }
}

移动之所以有效,是因为在移动之后,新对象应该与从其移出的对象相同,因此从观察者的角度来看,发射器没有改变。

与Java不同的原因是Java没有移动构造函数,因此没有(简单)的方式来表达“窃取观察者/资源”。