Bill Kotsias
Bill Kotsias

Reputation: 3358

Make only const copies of a const object

I have a class which contains references, like:

class A {
 A(B &b) : b(b) {} // constructor
 B &b;
}

Sometimes b must be read-only, sometimes it is writeable. When I make a const A a(b); object, it's obvious that I want to protect the data inside it as const. But - by accident - it's easy to make a non-const copy of the object which will make the data inside it vulnerable.

const A a(b); // b object protected here
A a_non_const(a);
a_non_const.b.non_const_function(...); // b not protected now

I think that I should somehow prevent copies of the object when it is const like this:

const A a(b);
const A a2(a); // OK!
A a_non_const(a); // Compiler error

Is this possible at all?

Upvotes: 2

Views: 119

Answers (2)

Daniel Jour
Daniel Jour

Reputation: 16156

flaw in your code: your data isn't "protected" even with const

The const type qualifier manages access to the member functions of a type as well as the access to its members. Since your member B & b is a reference, const doesn't do much for you here: A reference cannot be changed after initialization either way. How you access the target of that reference isn't even considered:

const A a(b);
a.b.non_const_function(); // OOPS, no problem!

solution with templates

Instead of (ab)using the const type qualifier you could add a "flag" to your type, to differentiate between cases where you need to be able to have non-const access and case where you don't:

#include <type_traits>

struct B {
    void danger() {
    }
    void all_fine() const {
    }
};

template<bool Writeable>
struct A {
    using BRef = typename std::conditional<Writeable, B &, B const &>::type;
    BRef b;

    A (BRef b) : b(b) {};
};

using ConstA = A<false>;
using NonConstA = A<true>;

int main() {
    B b;
    ConstA a(b);
    //NonConstA nc_a(a);
    ConstA another_a(a);
    //another_a.b.danger();
    another_a.b.all_fine();

    NonConstA a2(b);
    a2.b.danger();
}

With some std::enable_if you can then selectively enable / disable member functions of A depending on whether they need "writeable" b or not.

real solution: refactor your design

BUT I'd like to highlight this comment even more:

"Sometimes b must be read-only, sometimes it is writeable." All your problems stem from this weird duality. I suggest picking one set of semantics for your class, not two

From Lightness Races in Orbit

You should probably instead consider splitting your class such that you have a CommonA with functionality used by both a WriteableA and a NonWriteableA (the names are terrible, but I hope you understand what I mean).

Upvotes: 2

tevemadar
tevemadar

Reputation: 13195

You can do it for the heap:

static const A *constCopy(const A &a); // and of course implement it somewhere

Then you will not accidentally modify the object via the pointer you get (which has to be stored in const A *, otherwise the compiler will complain).

However it will not work with stack-based objects, as returning const A & of a local variable is a rather deadly action, and "const constructor" has not been invented yet (related: Why does C++ not have a const constructor?)

Upvotes: 2

Related Questions