Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does this code subvert the C++ type system?

Tags:

I understand that having a const method in C++ means that an object is read-only through that method, but that it may still change otherwise.

However, this code apparently changes an object through a const reference (i.e. through a const method).

Is this code legal in C++?

If so: Is it breaking the const-ness of the type system? Why/why not?

If not: Why not?

Note 1: I have edited the example a bit, so answers might be referring to older examples.

Edit 2: Apparently you don't even need C++11, so I removed that dependency.

#include <iostream>

using namespace std;

struct DoBadThings { int *p; void oops() const { ++*p; } };

struct BreakConst
{
    int n;
    DoBadThings bad;
    BreakConst() { n = 0; bad.p = &n; } 
    void oops() const { bad.oops(); }  // can't change itself... or can it?
};

int main()
{
    const BreakConst bc;
    cout << bc.n << endl;   // 0
    bc.oops();              // O:)
    cout << bc.n << endl;   // 1

    return 0;
}

Update:

I have migrated the lambda to the constructor's initialization list, since doing so allows me to subsequently say const BreakConst bc;, which -- because bc itself is now const (instead of merely the pointer) -- would seem to imply (by Stroustrup) that modifying bc in any way after construction should result in undefined behavior, even though the constructor and the caller would have no way of knowing this without seeing each others' definitions.

like image 399
user541686 Avatar asked Jun 18 '12 05:06

user541686


People also ask

What can C do that C++ cant?

On the other hand, C++ has tons of additional stuff that C can't do. Templates, polymorphism, operator overloading, etc, etc. C can mimic all of these things with different syntax, and there's no program you can write in one language that can't be written in the other language... so they're both equally capable.

What features does C have that C++ doesn t?

C does no support polymorphism, encapsulation, and inheritance which means that C does not support object oriented programming. C++ supports polymorphism, encapsulation, and inheritance because it is an object oriented programming language.

Is C included in C++?

C++ includes the standard C runtime library as a subset, although there are a few differences. If the C++ compiler provides its own versions of the C headers, the versions of those headers used by the C compiler must be compatible.


2 Answers

The oops() method isn't allowed to change the constness of the object. Furthermore it doesn't do it. Its your anonymous function that does it. This anonymous function isn't in the context of the object, but in the context of the main() method which is allowed to modify the object.

Your anonymous function doesn't change the this pointer of oops() (which is defined as const and therefore can't be changed) and also in no way derives some non-const variable from this this-pointer. Itself doesn't have any this-pointer. It just ignores the this-pointer and changes the bc variable of the main context (which is kind of passed as parameter to your closure). This variable is not const and therefore can be changed. You could also pass any anonymous function changing a completely unrelated object. This function doesn't know, that its changing the object that stores it.

If you would declare it as

const BreakConst bc = ...

then the main function also would handle it as const object and couldn't change it.

Edit: In other words: The const attribute is bound to the concrete l-value (reference) accessing the object. It's not bound to the object itself.

like image 112
Heinzi Avatar answered Oct 23 '22 06:10

Heinzi


You code is correct, because you don't use the const reference to modify the object. The lambda function uses completely different reference, which just happen to be pointing to the same object.

In the general, such cases does not subvert the type system, because the type system in C++ does not formally guarantee, that you can't modify the const object or the const reference. However modification of the const object is the undefined behaviour.

From [7.1.6.1] The cv-qualifiers:

A pointer or reference to a cv-qualified type need not actually point or refer to a cv-qualified object, but it is treated as if it does; a const-qualified access path cannot be used to modify an object even if the object referenced is a non-const object and can be modified through some other access path.

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.

like image 26
Rafał Rawicki Avatar answered Oct 23 '22 05:10

Rafał Rawicki