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?
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!
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.
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
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).