Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying const object through pointer obtained during construction

Tags:

c++

constants

I just discovered how easy it is to modify const objects without any const_cast black magic. Consider:

#include <iostream>

class Test {
public:
    Test(int v)
        :m_val{ v },
        m_ptr{ &m_val }
    {}

    int get() const { return m_val; }
    void set(int v) const { *m_ptr = v; }

private:
    int m_val;
    int* m_ptr;
};

int main()
{
    const Test t{ 10 };

    std::cout << t.get() << '\n';
    t.set(0);
    std::cout << t.get() << '\n';

    return 0;
}

Recent versions of Clang, GCC, and MSVC don't show any warning and produce expected output:

10 0

Is this well defined behavior according to the current standard? If it's undefined what if m_val was of type std::aligned_storage_t<sizeof(int), alignof(int)> and constructor new'ed int in it? I believe it's pretty common case when it comes to small buffer optimizations.

Edit

Thanks, it seems that it's just another way to shoot yourself in a foot. What's troubling it seems that this:

struct Test2 {
    int i;
    void operator()() { ++i; }
};

const std::function<void()> f{ Test2{ 10 } };
f();

is also undefined behavior when implementation chooses to store the Test2 object inside f (and that's the case in libc++ and in Visual Studio)

like image 443
codicodi Avatar asked Oct 27 '16 20:10

codicodi


People also ask

Can a const pointer be modified?

const int * is a pointer to an integer constant. That means, the integer value that it is pointing at cannot be changed using that pointer.

Can you change what a const pointer points to?

A pointer to constant is a pointer through which the value of the variable that the pointer points cannot be changed. The address of these pointers can be changed, but the value of the variable that the pointer points cannot be changed.

Can you change a const pointer C++?

Because the data type being pointed to is const, the value being pointed to can't be changed. We can also make a pointer itself constant. A const pointer is a pointer whose address can not be changed after initialization.

What is a const object CPP?

Const member functions in C++ C++ProgrammingServer Side Programming. The const member functions are the functions which are declared as constant in the program. The object called by these functions cannot be modified. It is recommended to use const keyword so that accidental changes to object are avoided.


2 Answers

const enforces "bitwise constness", but what you usually want is "logical constness".

In the case of an object that contains a pointer, this means that a const member function can't modify the pointer itself, but can modify what the pointer refers to. In other words, these examples are well formed, but have undefined behavior.

To get logical constness, you 1) use mutable (or sometimes const_cast) to allow modification of members that don't affect the object's logical state (e.g., cached values/memoization), and 2) generally have to manually enforce not writing to data through a pointer (but if it's an owning pointer, that ownership should probably be delegated to an object that only manages ownership of that data, in which case making it const should normally prevent writing to the data it owns).

As far as the specific detail of having a non-const pointer pointing to data that might itself have been const modified, well, you're basically just getting a (persistent) version of roughly the same thing that const_cast is typically used to do: get non-const access to data to which you'd otherwise only have a const pointer. It's up to you to ensure that you only use this in ways that doesn't cause a problem (but just having and/or writing through that pointer doesn't, in itself, necessarily lead to a problem).

In other words, what we have here are two separate pointers to some data. this lets you access an object's data. In a const member function, you can only read (not) write data via this, unless (as noted above) it's marked mutable. In this case, you're saving a second pointer to the same data. Since there's nothing to mark that as a pointer to const, it's not, so you get non-const access to the data it points at.

like image 106
Jerry Coffin Avatar answered Sep 30 '22 18:09

Jerry Coffin


As others pointed out in comments: you are modifying object the m_ptr points to. This "pointed to" object is not a part of class Test (as far as compiler sees it). That's why compiler allows you to do so.

Having said that, I believe that it will be undefined behaviour. That's because m_ptr actually points to another member variable (m_val) of object const Test t! Compilers are allowed to optimize arggresively and they might rely on constness to do so.

The only exception is then you use mutable keyword, but it's another story.

like image 34
Lehu Avatar answered Sep 30 '22 18:09

Lehu