Reputation: 1690
Suppose that we have a class A
with a member function f
.
To the outside world, f
simply computes a value without modifying anything of A
; but in the implementation, it does temporarily modify A
:
class A
{
int f() const
{
tiny_change(b); // since copying "b" is expensive
int result = compute(b);
tiny_recover(b); // "b" backs to the original value
return result;
}
B b;
}
Of course the code above does not compile. Here are two workarounds I know:
const_cast<A*>(this)->b
mutable B b;
None of these solutions is perfect. The solution 1 involves UB when an instance of A
itself is const
; and the solution 2 exposes the mutable-ness to the whole class such that it cannot prevent the coder from accidentally modifying b
in other const
member functions.
const_cast
is "local", but may trigger UB; mutable
is memory-safe, but too "global".
So is there a third solution, or am I understanding something wrong?
Upvotes: 2
Views: 170
Reputation: 19721
One possibility would be to encapsulate B
in a class that has it mutable
, but when it is const normally only allows const
access, except that it befriends A::f
. For example like this (untested code):
class A
{
int f() const;
int g() const; // some function without exclusive access
class B_wrapper
{
friend int A::f() const;
public:
B& get() { return object; }
B const& get() const { return object; }
private:
B& get_mutable() const { return object; }
mutable B object;
};
B_wrapper bw;
};
int A::f() const
{
B& b = bw.get_mutable(); // allowed due to friend declaration
tiny_change(b); // since copying "b" is expensive
int result = compute(b);
tiny_recover(b); // "b" backs to the original value
return result;
}
int A::g() const
{
// B& b = bw.get_mutable();
// -> not allowed because B_wrapper::get_mutable() is private
// B& b = bw.get();
// -> not allowed because get() const returns a const reference
B const& b = bw.get();
// without casts, only const interface to b is available
}
Upvotes: 2