You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何强制子类拷贝构造函数锁定基类中声明的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
}

方案优势

  1. 避免虚函数陷阱:通过static_cast<T*>(this)直接调用子类非虚方法,无需依赖虚函数表,彻底解决构造阶段调用纯虚函数的问题。
  2. 强制子类实现:基类将copy_impl声明为protected且=delete,子类若不实现该方法会直接编译报错,达到约束目的。
  3. 零子类额外代码:子类只需实现核心拷贝逻辑copy_impl,拷贝构造和赋值运算符由编译器自动生成,互斥锁锁定逻辑完全由基类处理,符合需求。

内容的提问来源于stack exchange,提问作者user3641187

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:27:59