1

As far as I know , making constant functions in a class is useful for read/write compiler optimizations.

A constant function within a class means that the class members will remain constant during the execution of the function. However, you can bypass this by const casting the implicit parameter (ofc this is a very bad practice).

My questions is as follows :

What pitfalls can the following code cause (especially in terms of performance unrelated to thread synchronization) ?

 int myClass::getSomething() const
 {
     myClass* writableThis = const_cast<myClass*>(this);
     writableThis->m_nMemberInt++;
     ...
     return m_nSomeOtherUnchangedMember;
 }

Another related question :

Is the behavior compiler/platform/os specific ?

I would also very much appreciate if someone could explain the magic under the hood when such a code is compiled/executed (I'm speculating that the CPU is making out-of-order optimizations based on the fact that the function is const , and not respecting this during actual execution should have some side effects).

EDIT :

Thank you for clarifying this for me. After further research all the received answers are correct but I can accept only one :).

Regarding the const qualifier being used solely for syntax corectness , I believe this answer is both right and wrong, the correct way to state this (imho) would be that it is used mostly for syntax corectness (in a very limited number of scenarios it can produce different / better code ). References : SO Related question , related article

Community
  • 1
  • 1
MichaelCMS
  • 4,703
  • 2
  • 23
  • 29
  • Do you plan to store `myClass` in a `std` container? Will said `std` container ever be used in multithreaded environments? Will you ever (ever) create a `const myClass` anywhere? – Yakk - Adam Nevraumont Jan 05 '15 at 16:05
  • 1
    "As far as I know , making constant functions in a class is useful for read/write compiler optimizations." http://stackoverflow.com/questions/27466642/what-kind-of-optimization-does-const-offer-in-c-c/27466684#27466684 – ravi Jan 05 '15 at 16:05
  • 9
    The assumption first sentence is already incorrect. The main use of `const` is to help program correctness. – MSalters Jan 05 '15 at 16:07
  • 1
    Have a look at the `mutable` keyword. – pmr Jan 05 '15 at 16:22

5 Answers5

7

The const_cast<T>(this) trick is potentially unsafe, because the user of your member function may run into undefined behavior without doing anything wrong on their side.

The problem is that casting away const-ness is allowed only when you start with a non-const object. If your object is constant, the function that casts away its const-ness and uses the resultant pointer to change object's state triggers undefined behavior:

struct Test {
    int n;
    Test() : n(0) {}
    void potentiallyUndefinedBehavior() const {
        Test *wrong = const_cast<Test*>(this);
        wrong->n++;
    }
};

int main() {
    Test t1;
    // This call is OK, because t1 is non-const
    t1.potentiallyUndefinedBehavior();
    const Test t2;
    // This triggers undefined behavior, because t2 is const
    t2.potentiallyUndefinedBehavior();
    return 0;
}

The trick with const_cast<T>(this) has been invented for caching values inside member functions with const qualifier. However, it is no longer useful, because C++ added a special keyword for this sort of things: by marking a member mutable you make that member writable inside const-qualified methods:

struct Test {
    mutable int n;
    Test() : n(0) {}
    void wellDefinedBehavior() const {
        n++;
    }
};

Now the const member function will not trigger undefined behavior regardless of the context.

martinus
  • 17,736
  • 15
  • 72
  • 92
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

The CPU doesn't know anything about const, which is a C++ keyword. By the time the compiler has transformed the C++ code to assembly, there's not much left of that.

Of course, there's a real possibility that the generated code is entirely different because of the const keyword. For instance, the const version of some operator[] may return a T object by value whereas the non-const version must return a T&. A CPU doesn't even know what function it's in, or even assume the existence of functions.

MSalters
  • 173,980
  • 10
  • 155
  • 350
2

My answer is to use the storage class mutable for any thing which need to be modified in const methods.

It's built into the language, so there are several benefits. It's a tighter control for how const methods modify data members. Other developers will know these data members will change in const methods. If there are any compiler optimizations, the compiler will know to do the right thing.

class myClass {
private:
    int m_nSomeOtherUnchangedMember;
    mutable int m_nMemberInt;
    …

public:
    int getSomething() const;
    …
};

int myClass::getSomething() const
{
    m_nMemberInt++;
    …
    return m_nSomeOtherUnchangedMember;
}
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
2

As far as I know , making constant functions in a class is useful for read/write compiler optimizations.

No. We use const methods to enforce semantic guarantees, not to allow optimizations (with the possible exception of avoiding copies).

What pitfalls can the following code cause

  1. Firstly, it can break program semantics.

    For example, std::map nodes store std::pair<const Key, T>, because the Key shouldn't mutate after it has been inserted. If the key changes value, the map sorting invariant is incorrect, and subsequent find/insert/rebalance operations will misbehave.

    If you call a const-qualified method on this const key, and that method changes the Key in a way that affects how it compares, then you've cunningly broken the map.

  2. Secondly, it can kill your program. If you have a const object overlaid on a genuinely read-only address range, or you have a statically-initialized const object in the read-only initialized data segment, then writing to it will cause some kind of protection error

Useless
  • 64,155
  • 6
  • 88
  • 132
0

As other stated the const-correctness was designed as a help for the programmers and not an help for the optimizer. You should remember 4 things:

1. const references and const methods are not faster

2. const references and const methods are not faster

3. const references and const methods are not faster

4. const references and const methods are not faster

More specifically the optimizer simply completely ignores const-ness of references or of methods because const doesn't really mean in that context what you are thinking.

A const reference to an object doesn't mean that for example during the execution of a method the object will remain constant. Consider for example:

struct MyObject {
    int x;
    void foo() const {
        printf("%i\n", x);
        char *p = new char[10];
        printf("%i\n", x);
        delete[] p;
    }
};

the compiler cannot assume that x member didn't mutate between the two calls to printf. The reason is that std::operator new global allocator could have been overloaded and the code could have regular non-const pointer to the instance. Therefore it's perfectly legal for the global allocator to change x during the execution of foo. The compiler cannot know this is not going to happen (the global allocator could be overloaded in another compilation unit).

Calling any unknown code (i.e. basically any non-inlined function) can mutate any part of an object, being in a const method or not. The const method simply means that you cannot use this to mutate the object, not that the object is constant.

If const correctness is really an help for the programmers is another question on which I personally have a quite heretic point of view, but that's another story...

6502
  • 112,025
  • 15
  • 165
  • 265