Question

class Test
{
public:
    Test() : i(0), ptr(&i) {}
    int i;
    int *ptr;
    void change_const (int x) const { *ptr=x; }
};

int main()
{
    const Test obj;
    obj.ptr = &obj.i; // error
    obj.change_const(99);
    return 0;
}

Although in obj ptr is of type int *const, the constructor can make him point to i of type const int. An explicit try to do this of course fails. Why does a constructor offer this vulnerability regarding const correctness? Other non directly obvious vulnerabilities like

int *ptr;
const int **c_ptr = &ptr; // error
const int c = 10;
*c_ptr = &c;
*ptr = 20; // because here change of c possible

are also well thought prevented.

Was it helpful?

Solution 2

Clearly the constructor (or at least the initializer list if not the body of the ctor) needs to be able to write a value to i.

As it happens, the way C++ achieves this is to make this a pointer-to-non-const in the constructor (and destructor). Basically, the const-ness of obj doesn't commence until the constructor has finished executing. That's why the vulnerability exists, because of a straightforward but imperfect solution to the technical problem of how to construct const-qualified objects.

Perhaps it could in principle be done differently. I suppose you'd need a separate const version of the constructor in which the compiler applies different rules (just as normal member functions can be const), treating data members as const and therefore (1) allowing them to be initialized but not assigned, (2) forbidding the initialization of ptr from &i since the latter would have type int const*. C++ doesn't do this, and as a result it has this loophole that you've driven through. If it did do it, people would have more difficulty writing constructors in certain cases, so it's a design trade-off.

Be aware that similarly a volatile-qualified object is not volatile in its own constructor or destructor.

OTHER TIPS

const is a language-level concept. That is, when you compile your code and execute it as machine code, all data is seen as data more or less. Note that I say "more or less" because we are ignoring the fact that, in theory, const data could be stored in read-only pages and trigger page faults when written to; but this is not common due to the granularity of page sizes. So what is happening is the following:

Your constructor initializes that value of ptr to point to the address of i. Since your obj object is const, you could not directly modify the value of i and, further, you could not change where ptr points to. However, you can access and manipulate the memory that ptr points to (in this case, the value of i).

Therefore, since the compiler doesn't check/know/care that ptr is pointing to i, it does not catch the violation of const. Instead, it just sees you modifying the data pointed to by ptr.

Steve Jessop answered it, but for what it's worth, here is the quote from the Standard (emphasis mine):

12.1/4 A constructor shall not be virtual (10.3) or static (9.4). A constructor can be invoked for a const, volatile or const volatile object. A constructor shall not be declared const, volatile, or const volatile (9.3.2). const and volatile semantics (7.1.6.1) are not applied on an object under construction. They come into effect when the constructor for the most derived object (1.8) ends. A constructor shall not be declared with a ref-qualifier.

So *this is not a constant object from the point of view of the constructor, even when a constant object is created. This could have been designed differently, but then constructors of constant objects would be much less flexible than constructors of non-constant objects; for example, they would always have to initialize all members in the initializer list; they could not use loops etc. in the body of the constructor to set values for complex members.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top