0

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?

BWG
  • 2,238
  • 1
  • 20
  • 32
  • const pointer vs pointer to const - http://stackoverflow.com/questions/10091825/constant-pointer-vs-pointer-on-a-constant-value – Michael Gazonda Jan 20 '15 at 03:06
  • @MichaelGazonda I understand that and it doesn't answer my question at all. – BWG Jan 20 '15 at 03:07
  • Just never use `const`. None of the good programmers do. It's just a pain. *cough* – David Jan 20 '15 at 03:15
  • My advice would be *do use const* ; it will catch many (but not all) errors, and help the compiler to optimize your code. The problem in this post is that OP hasn't defined the semantics of the relationship between an `a` and the thing that an `a::p` is pointing to. – M.M Jan 20 '15 at 03:26
  • @MattMcNabb How would I define the semantics? I don't even know what that means. – BWG Jan 20 '15 at 03:35
  • @BWG my answer discusses this. You have to decide whether an object of type `const a` should allow the thing that `p` points to to be modified. Nobody can decide this for you (as posted) because we don't know what problem your code is trying to solve – M.M Jan 20 '15 at 03:37
  • As written, `b *p;` means that the thing being pointed to may be modified, even for `p` being a member of a `const a`. – M.M Jan 20 '15 at 03:39
  • @MattMcNabb OK, I understand now. I've decided to nuke all const in my object to avoid code duplication. – BWG Jan 20 '15 at 03:40

1 Answers1

2

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

M.M
  • 138,810
  • 21
  • 208
  • 365
  • But there are const variables. `ii` is a pointer to a `const`, which means in theory I shouldn't be able to modify what it points to, but I clearly can. – BWG Jan 20 '15 at 03:18
  • OK, I see what you mean. I'll modify my question. Nah, nevermind, I think I get it. – BWG Jan 20 '15 at 03:23