XXXHHHH
XXXHHHH

Reputation: 110

ensure class member variables are not modified when cloning

I am trying to add a clone func for class A. This class has a non const and not owned pointer b_. I want to make sure that b_ wont be modified in the cloned objects, but it is ok to modify other member variables, and these non-const func in A can still be called.

A bad way is adding a flag and check it every time before modifying b_. It is bad because if a new func in A is added, some one else might forget to check it.

Is there a better way to achieve this goal?

Here is my bad solution mentioned above:

class A {
 public:
  A* clone() const {
    auto* clone = new A(*this);
    clone->is_cloned_ = true;
    return clone;
  }
  void DoSomething() {
    if (!is_cloned_){
      b_->NonConstFunc();
    }
  }

  void DoSomethingElse() {
    other_values = 2; // cloned versions can modify this.
  }
 private:
  is_cloned_ = false;
  B* b_; // Not owned
  int other_values = 1;
}

Upvotes: 2

Views: 81

Answers (2)

catnip
catnip

Reputation: 25388

You could perhaps design a class hierarchy like this:

class cloned_A;

class A
{
public:
    cloned_A *clone ();    
private:
    B* b_;
};

class cloned_A : public A
{
public:
    cloned_A (const B *b) : read_only_b (b) {}
private:
    const B* read_only_b;
};

cloned_A *A::clone ()
{
    return new cloned_A (b_);
}

Now b_ is private to A and the cloned object can only access read_only_b via a const pointer and therefore cannot modify it.

Upvotes: 2

Jarod42
Jarod42

Reputation: 217135

A way to avoid issue when adding method to A is to wrap the logic to access B in its own class:

class ProtectedB
{
public:
    ProtectedB(B& b) : b(&b) {}
    ProtectedB(const ProtectedB& rhs) : b(rhs.b), cloned(true) {}

    // Duplicate public B interface
    void NonConstFunc() {
        if (cloned){ return; }
        b->NonConstFunc();
    }

   // Possibly (might avoid to duplicate non mutable interface of B)
   const B& GetB() const { return *b; };
private:
    B* b = nullptr;
    bool cloned = false;
};

Then A is simply:

class A {
public:
    // ...

    std::unique_ptr<A> clone() const { return std::make_unique<A>(*this); }
    void DoSomething() { b.NonConstFunc(); }
    void DoSomethingElse() { other_values = 2; } // cloned versions can modify this.

private:
    ProtectedB b;
    int other_values = 1;
};

Upvotes: 0

Related Questions