如何强制子类拷贝构造函数锁定基类中声明的mutex?
问题:强制子类拷贝操作自动锁定基类互斥锁
我有一个包含mutex的基类,所有继承类都需要具备锁定状态的能力。我希望强制所有子类的拷贝构造函数和赋值运算符都能锁定该mutex,且无需在子类实现中手动指定。
目前我采用了如下模式,将子类的所有深拷贝操作封装在一个独立的虚方法中,以此提醒子类实现需要处理深拷贝操作:
#include <iostream> #include <mutex> template<typename T> class baseclass { public: mutable std::mutex mtx; // 强制子类实现拷贝方法 virtual void child_copy(T const& other)=0; baseclass<T>()=default; // 拷贝构造函数 baseclass<T>(baseclass<T> const& other){ std::unique_lock<std::mutex> lock_other(other.mtx); copy_from(other); } // 拷贝赋值运算符 baseclass& operator=(baseclass const& other) { if (&other != this) { std::unique_lock<std::mutex> lock_this(mtx, std::defer_lock); std::unique_lock<std::mutex> lock_other(other.mtx, std::defer_lock); std::lock(lock_this, lock_other); copy_from(other); } return *this; } private: void copy_from(baseclass const& other) { std::cout<<"calling copy_from"<<std::endl; static_cast<T*>(this)->child_copy(static_cast<T const&>(other)); std::cout<<"done calling copy_from"<<std::endl; } }; class Implementation : public baseclass<Implementation>{ public: int state{}; void child_copy(Implementation const& other) override{ std::cout<<"calling child_copy"<<std::endl; state = other.state; } }; int main(){ Implementation A; Implementation B(A); // 错误发生在这里 }
但我遇到了错误:libc++abi: Pure virtual function called!,似乎是static_cast<T*>(this)->child_copy(static_cast<T const&>(other))导致的问题。
是否存在可行的方式来实现这一预期模式?
错误原因
C++中,基类构造函数执行期间,子类对象尚未完成构造,此时对象的虚函数表仍属于基类。调用纯虚函数child_copy会触发未定义行为,直接导致程序崩溃。
解决方案:基于CRTP的非虚函数约束
利用奇异递归模板模式(CRTP),绕过虚函数机制,让基类直接调用子类的非虚拷贝方法,同时强制子类必须实现该方法。这样既避免了构造阶段调用虚函数的问题,又能让基类统一处理互斥锁逻辑,子类无需手动编写拷贝构造/赋值运算符。
修正后的代码:
#include <iostream> #include <mutex> template<typename T> class baseclass { public: mutable std::mutex mtx; baseclass() = default; // 拷贝构造:基类统一处理锁定,直接调用子类拷贝逻辑 baseclass(baseclass const& other) { std::unique_lock<std::mutex> lock_other(other.mtx); static_cast<T*>(this)->copy_impl(static_cast<T const&>(other)); } // 拷贝赋值:同样统一处理双锁逻辑,调用子类拷贝实现 baseclass& operator=(baseclass const& other) { if (&other != this) { std::unique_lock<std::mutex> lock_this(mtx, std::defer_lock); std::unique_lock<std::mutex> lock_other(other.mtx, std::defer_lock); std::lock(lock_this, lock_other); static_cast<T*>(this)->copy_impl(static_cast<T const&>(other)); } return *this; } protected: // 声明为delete,强制子类必须实现自己的copy_impl方法 void copy_impl(T const& other) = delete; }; class Implementation : public baseclass<Implementation> { public: int state{}; // 子类必须实现的拷贝逻辑,基类会自动调用 void copy_impl(Implementation const& other) { std::cout << "执行子类拷贝逻辑" << std::endl; state = other.state; } }; int main() { Implementation A; A.state = 42; Implementation B(A); // 正常执行,输出"执行子类拷贝逻辑" std::cout << B.state << std::endl; // 输出42 Implementation C; C = B; // 正常执行,输出"执行子类拷贝逻辑" std::cout << C.state << std::endl; // 输出42 }
方案优势
- 避免虚函数陷阱:通过
static_cast<T*>(this)直接调用子类非虚方法,无需依赖虚函数表,彻底解决构造阶段调用纯虚函数的问题。 - 强制子类实现:基类将
copy_impl声明为protected且=delete,子类若不实现该方法会直接编译报错,达到约束目的。 - 零子类额外代码:子类只需实现核心拷贝逻辑
copy_impl,拷贝构造和赋值运算符由编译器自动生成,互斥锁锁定逻辑完全由基类处理,符合需求。
内容的提问来源于stack exchange,提问作者user3641187
相关产品推荐
相关产品推荐

