0

I have a base class with a mutex since all inheriting classes need the ability to lock state. I want to force all children copy and assignment constructors to lock the mutex, ideally without having to specify so manually in the child implementation.

So far I came up with this pattern which encapsulates all deepcopy actions of a child in a separate virtual method, hereby also reminding child implementations that deep copy operations need to be taken care of:

#include <iostream>
#include <mutex>

template<typename T>
class baseclass {
public:
    mutable std::mutex mtx;
    // forcing children to implement a copy method
    virtual void child_copy(T const& other)=0;
    baseclass<T>()=default;
    // Copy constructor
    baseclass<T>(baseclass<T> const& other){
        std::unique_lock<std::mutex> lock_other(other.mtx);
        copy_from(other);
    }

    // copy assignment operator
    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); // ERROR HERE

}

However I'm getting an error: "libc++abi: Pure virtual function called!". It appears that static_cast<T*>(this)->child_copy(static_cast<T const&>(other)) is causing the error.

Is there a working way to enforce the desired pattern?

user3641187
  • 405
  • 5
  • 10
  • You might consider a [non-virtual interface](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface). – Eljay Feb 26 '23 at 22:34
  • You are using an implicitly defined `Implementation` copy constructor, which will first copy `baseclass`. And copying your `baseclass` will indeed call your pure virtual function. – Drew Dormann Feb 26 '23 at 22:38
  • When you are in the constructor of the base class, the derived class v-table hasn't been setup yet. `copy_from`, when invoked from the base class constructor, will invoke baseclass's implementation, not the derived class. Same goes for the destructor. – selbie Feb 26 '23 at 22:38
  • @Eljay I believe the non-virtual interface idiom would still create the same problem if applied to copy constructor..? – user3641187 Feb 26 '23 at 22:50
  • Re: "I want to force..." -- why? It's possible that a derived class could be copied or assigned without having to be locked until the base operation runs. For example, a derived class that doesn't have any data of its own can certainly be copied correctly by only locking inside the code that copies the base part. – Pete Becker Feb 26 '23 at 23:16
  • For **polymorphic** copy "construction", a pretty common pattern is to use a *clone* idiom. – Eljay Feb 27 '23 at 00:12

0 Answers0