const access paths and non-const objects

S

shurjyaprabha ray

I have the following code:
(Yes, I understand there is a circular
dependency and that this is a Bad
Thing to do, but bear with me.)

struct a;
struct b {
a* a_;
b() : a_(0) {}
void set(a* t) { a_ = t; }
void change();
};

struct a {
int data_;
b& b_;
a(b& s) : b_(s), data_(42) {}
void strange() const {
b_.change();
}
};

void b::change() {
if (!a_)
a_->data_ = -42;
}

int main()
{
b m;
a n(m);
m.set(&n);

n.strange();
}

I consulted the draft n3090 and have problems
interpreting 7.1.6.1 §3 and §4. I read them as:
Since there is a const access path in a::strange
the call results in undefined behavior. Is this
correct? Or, is it that it invokes UB only in the
case that the object n was originally declared
const? (Yes, I consulted 9.3.2 §1 and §2 in
conjunction to the sections mentioned above.)

Any help would be greatly appreciated.
 
S

SG

struct a;

struct b {
    a* a_;
    b() : a_(0) {}
    void set(a* t) { a_ = t; }
    void change();
};

struct a {
    int data_;
    b& b_;
    a(b& s) : b_(s), data_(42) {}
    void strange() const {
        b_.change();
    }
};

void b::change() {
    if (!a_)
        a_->data_ = -42;
}
[snip]

I consulted the draft n3090 and have problems
interpreting 7.1.6.1 §3 and §4. I read them as:
Since there is a const access path in a::strange
the call results in undefined behavior. Is this
correct? Or, is it that it invokes UB only in the
case that the object n was originally declared
const? (Yes, I consulted 9.3.2 §1 and §2 in
conjunction to the sections mentioned above.)

This is not UB. And if you declared your object of class a to be const
you wouldn't be able to call b::set(a*) without a const_cast. But
with

const a mya = ...;
...
myb.set(const_cast<a*>(&mya));

you would get UB. There is a difference between an object that is
"actually const" and an "access path" that yields a const lvalue. In
the latter case, the "view" is only const and not necessarily the
object itself.

int main() {
double foooobar = 1.68;
const double pi = 3.14159265;
const double* p1 = &foooobar;
const double* p2 = &pi;
const_cast<double&>(*p1) = 99; // OK, foooobar is not const
const_cast<double&>(*p2) = 99; // UB! pi is const!
}

As for a::strange being a const member function. Its data element is
not changed via the access path this->data_ but the access path *(this-
b.a) which yields a non-const lvalue referring to a data member of a
non-const object. This is fine.

Cheers!
SG
 
S

shurjyaprabha ray

On 15 Aug., 01:13, shurjyaprabha ray wrote:

[...]
I consulted the draft n3090 and have problems
interpreting 7.1.6.1 §3 and §4. I read them as:
Since there is a const access path in a::strange
the call results in undefined behavior. Is this
correct? Or, is it that it invokes UB only in the
case that the object n was originally declared
const? (Yes, I consulted 9.3.2 §1 and §2 in
conjunction to the sections mentioned above.)

This is not UB. [...]

Thank you both. I understand now. Somehow, I assumed
const-ness would be naturally transitive (i.e.
passed on to by member pointers/references to the
pointed/referenced-to-resources).

And yes, thanks to Paavo for pointing out the bug!

(Yes, I feel kinda stupid now ...)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top