Reputation: 2278
I'm learning to despise const
.
struct b;
struct a {
b* p;
void nonConst() { p = nullptr;}
b* getP() const { return p;}
};
struct b {
a *p;
a *getP() const { return p;}
};
void func (const a *ii) {
b *uRef = ii->getP();
//dear god, we've just obtained a pointer to a non-const a, starting with const a
a *iii = uRef->getP();
//and we've just modified ii, a const object
iii->nonConst();
}
int main() {
a *i = new a;
b *u = new b;
i->p = u;
u->p = i;
func(i);
}
Could this induce any undefined behavior? If not, is it breaking any const
rules? If not that, why is this
treated as a const
pointer to const
data, and not just a const
pointer to non-const
data?
Upvotes: 0
Views: 357
Reputation: 141554
There are no const
variables in your code, so there is no UB.
In void func (const a *ii)
, the const
means ii
might either be pointing to an a
or a const a
, so we shouldn't allow writing through this pointer in case it actually points to a const a
.
But in your code it doesn't actually point to a const a
.
The underlying issue you seem to be having is related to the basic structure:
struct C
{
std::string *ptr;
};
In this case, if we have a variable:
const C c = something;
then the question is, should it be permitted to write:
*(c.ptr) = "Hello";
The rules of C++ say "Yes, this is fine". This is because c.ptr
is const
, but the thing being pointed to is not const
.
The question of whether or not this is actually a good idea is something that you have to decide on as part of your class interface (which you will describe in your class's documentation).
If the value of the string is supposed to be an invariant for instances of C
, then you may want to disallow this, or at least, discourage it.
Back to your original code, if you want a const a
to represent holding a const b
, then you would need to put:
b const * getP() const { return p;}
^^^^^
and then the caller will not be able to write b *uRef = ii->getP();
, they'd have to at least throw in a const_cast
.
Finally, there isn't an easy way for a const a
to actually hold a b const *
, but a non-const a
to hold a b *
. A simpler solution is to actually have two different classes here (say a
and const_a
).
Upvotes: 2