【问题标题】:Copy constructor on "Observer pattern"复制“观察者模式”上的构造函数
【发布时间】:2019-10-03 16:03:16
【问题描述】:

假设我们有一个类似的设计模式:

#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++ 的答案可能会改变

【问题讨论】:

  • 您能否详细说明“使它们与std::vector...兼容”和“发射器出现的问题”的意思?
  • NVM。阅读 Artyer 的回答后明白了你的意思。

标签: c++


【解决方案1】:

移动构造函数是合适的:

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

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

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

【讨论】:

  • 最好显式删除复制并添加移动赋值运算符。
猜你喜欢
  • 2019-05-12
  • 1970-01-01
  • 2016-02-20
  • 2023-04-10
  • 1970-01-01
  • 2010-09-23
  • 2011-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多