C++观察者模式:如何约束类对象避免被重新分配?
问题:如何约束C++类对象避免被重新分配?
在某些场景下(比如使用std::vector时),对象会被重新分配内存,这会给C++观察者模式的实现带来问题。
根据《四人帮》(Gang of Four)书籍中的定义,可观察对象的实现如下:
class ObservableSubject { public: virtual ~ObservableSubject() = default; virtual void notify() = 0; protected: ObservableSubject() = default; private: std::vector<Observer*> mObservers; };
Observer类的实现如下:
class Observer { public: virtual ~Observer() = default; virtual void update(ObservableSubject& subject) = 0; protected: Observer() = default; };
考虑以下示例:
class Mapper final: public Observer {};
当Mapper对象被存储在std::vector<Mapper>中时,一旦std::vector触发内存重新分配,mObservers中保存的指针就会失效。常规解决方案是改用指针(比如std::shared_ptr),用std::vector<std::shared_ptr<Mapper>>来存储,但这种方案要求开发者必须刻意避免让Mapper对象被重新分配,存在人为失误的隐患。
请问是否存在方法可以在C++中约束某个类,使其对象无法被重新分配?
解决方案:禁止类的拷贝与移动操作
对象被重新分配的核心原因是std::vector扩容时会执行拷贝/移动构造操作,将旧内存中的对象复制到新内存后销毁旧对象。因此,只要禁止类的拷贝和移动相关操作,就能从根源上阻止对象被重新分配。
具体实现方式
显式删除特殊成员函数:在目标类中直接删除拷贝构造、拷贝赋值、移动构造、移动赋值这四个特殊成员函数,编译器会在尝试拷贝/移动对象时直接报错:
class Mapper final: public Observer { public: // 禁止拷贝操作 Mapper(const Mapper&) = delete; Mapper& operator=(const Mapper&) = delete; // 禁止移动操作 Mapper(Mapper&&) = delete; Mapper& operator=(Mapper&&) = delete; };复用不可拷贝基类:定义一个通用的不可拷贝/移动基类,让需要约束的类继承它,避免重复编写代码:
class NonRelocatable { public: NonRelocatable(const NonRelocatable&) = delete; NonRelocatable& operator=(const NonRelocatable&) = delete; NonRelocatable(NonRelocatable&&) = delete; NonRelocatable& operator=(NonRelocatable&&) = delete; protected: NonRelocatable() = default; ~NonRelocatable() = default; }; class Mapper final: public Observer, public NonRelocatable {};
效果
当尝试将Mapper对象放入std::vector<Mapper>并触发扩容时,编译器会直接抛出错误——因为std::vector无法执行必要的移动/拷贝操作,从编译阶段就彻底阻止了对象被重新分配的可能。
内容的提问来源于stack exchange,提问作者yonutix
相关产品推荐
相关产品推荐

