In following example const object can modify itself via const method, because in that method it acces itself via non-const pointer. (same program on ideone)
#include <iostream>
struct Object;
Object * g_pObject;
struct Object
{
Object():m_a(0){}
void ModifySelfViaConstMethod() const
{
g_pObject->m_a = 37;
}
int m_a;
};
int main()
{
Object o;
g_pObject = &o;
const Object & co = o;
std::cout << co.m_a << "\n";
co.ModifySelfViaConstMethod();
std::cout << co.m_a << "\n";
return 0;
}
I am not so good with reading c++ standard, so I ask here:
What does standard says about this?
a)const method doesn't guarantee you that your object stays unmodified when you do stuff like this
b) Is it well defined that and it must compile
c) other ?
When you declare a const function, it's "for your own good".
In other words, you declare it const because according to your initial design, it is not supposed to change any object with which it will be invoked during runtime.
If during some later point in the implementation of this function you end up changing the object, the compiler will "yell at you", telling you it's wrong.
Of course, the compiler will be able to identify such attempt, only when applied on this.
In the given example, the compiler cannot identify the problem because it requires a comparison between this and g_pObject, and such comparison can only take place during runtime.
When a method is declared as const, the compiler ensures that the instance pointed to by the this pointer is not modified. If you try to modify the this instance, the compiler to fail. However, the compiler has no way of knowing that g_pObject and this are actually pointing at the same instance. That requires a run-time comparison, and no compiler is going to waste time performing run-time comparisons of every pointer used inside of a const method in the off-chance that they might match the this pointer. So if you are going to modify an Object via an external pointer, you are going to have to do your own check, eg:
void ModifySelfViaConstMethod() const
{
if (g_pObject != this)
g_pObject->m_a = 37;
}
What does standard says about this?
It says (paraphrasing) that this has type const Object *, so that you can't directly modify members or call non-const member functions via this. It says nothing about what you can do with any global variables that the function might have access to; it only controls direct access to the object the function is called on.
const method doesn't guarantee you that your object stays unmodified when you do stuff like this
No it doesn't. It states the intent that the function won't modify the object, and provides some protection against accidentally breaking that intent. It doesn't prevent a suitably deranged programmer from using const_cast, or (as here) uncontrolled coupling via global variables to break the promise.
Is it well defined that and it must compile
Yes. o is not itself constant, so there's nothing to stop you taking a non-const pointer or reference to it. The const on the member function only restricts access to the object via this, not to arbitrary objects via other pointers.
Constancy in C++ is a safety instrument, not security.
The code where constancy is honored will most probably work as expected, and all unintentional attempts to cast constancy away will be alerted by the compiler.
In cases when "I know what I am doing" one can find the whole variety of tools, from const_cast operator and mutable keyword to the banal C style cast.
Related
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
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.
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.
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;
}
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
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.
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
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...
I would like to ask a question about methods' const-correctness. Let me illustrate the situation.
class MyClass
{
public:
...
void DiscussedMethod() { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
I have a class MyClass which keeps a pointer to OtherClass. In DiscussedMethod it calls OtherClass::NonConstMethod which modifies some visible data.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)? Would it be a bad practice? Or is both fine?
What if the OtherClass kept a pointer to the MyClass and in NonConstMethod modified some of the MyClass' data (meaning that the MyClass member data would change during the DiscussedMethod call). Would it be a bad practice to make the DiscussedMethod const then?
As far as I've been able to find out, the const on a method is mostly a code documenting thing, so I would probably lean toward to not making the DiscussedMethod const, but I would like to hear your opinions.
EDIT: Some replies take the into account whether the object pointed to by otherClass is owned by the MyClass object. This is not the case in the scenario I'm working with. Lets say that both objects exist independently side by side (with the ability to modify each other). I think this analogy describes my situation quite well.
For example consider something like doubly-linked list, where each element is a class that keeps pointer to its neighbours and member variable color. And it has method MakeNeighboursRed which changes the color of its neighbours but doesn't affect the calling object's state itself. Should I consider making this method const?
And what if there was some possibility that MakeNeighboursRed would call neighbour's MakeNeighboursRed. So in the end the state of the object for which MakeNeighboursRed has been called originally would change as well.
And I would like to thank you all for your opinions :-)
If MyClass owns the OtherClass instance i wouldn't make DiscussedMethod constant.
The same goes for classes, managing resources. I.e. the standard containers do not return non const references or pointers to the managed memory using const functions, although it would be "possible" (since the actual pointer holding the resource is not modified).
Consider
class MyClass
{
public:
bool a() const { return otherClass->SomeMethod(); }
void b() const { otherClass->NonConstMethod(); }
private:
OtherClass *otherClass;
};
void foo (MyClass const &x)
{
cout << boolalpha << x.a() << endl;
x.b(); // possible if b is a const function
cout << boolalpha << x.a() << endl;
}
The foo could print two different values although an implementor of foo would probably expect that two function calls on a const object will have the same behaviour.
For clarification:
The following is invalid according to the standard since the const version of operator[] returns std::vector<T>::const_reference which is a constant reference to the value type.
std::vector<int> const a = { /* ... */ };
a[0] = 23; // impossible, the content is part of the state of a
It would be possible if there was only one signature of this function, namely referece operator[] (size_t i) const;, since the operation does not alter the internal pointers of the vector but the memory they point to.
But the memory, managed by the vector is considered to be part of the vectors state and thus modification is impossible through the const vector interface.
If the vector contains pointers, those pointer will still be unmodifiable through the public const vector interface, although the pointers stored in the vector may well be non const and it may well be possible to alter the memory they point to.
std::vector<int*> const b = { /* ... */ };
int x(2);
b[0] = &x; // impossible, b is const
*b[0] = x; // possible since value_type is int* not int const *
In OOP object should be fully described by its state, available through its interface. Thus, const methods should not alter object's state, if these changes might be observed through the interface.
A good example is a mutable mutex inside your class to guard some shared resources. It might be modified from const method, since it does not introduce any changes observable via class interface.
General rule of thumb is, that if you can make a member function const, you probably should. The reason for that is that it allows you to catch unintended behaviour and bug easier.
Another argument in favor would be that if you have this function as const you are allowed to call it on const object, so it isn't really a documentation thing.
Overall it depends what the other class is. It's not black and white...
If otherClass is a log object (for example) and you want to log the operation of the current object then it's perfectly fine calling it from a const function.
If the otherClass is a container that for design (or implementation) purposes is implemented as a separate object than effectively a const function modifies the object making this a very bad idea.
I hope this helps.
It's totaly incorrect to make DiscussedMethod const as it changes it's *this state. The only loophole to this is making non-logically-part-of-object's-state member data mutable so they can be changed in const functions. This would be things like a member that hold a count for "number of times function x() has been called". Any thing else is part of the object's state, and if a function changes it (at any level), that function isn't const.
I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)?
otherClass is member data, and it (or rather, the object it points to) gets modified.
Consider the semantics should the pointer to otherClass be refactored to a fully-owned object... whether something is held as a pointer, reference, or object doesn't change the semantical ownership, IMO.
class A
{
...
public:
shared_ptr<Logger> GimmeLogger () const
{
return m_logger;
}
private:
shared_ptr<Logger> m_logger;
};
In class A, should GimmeLogger be const or non-const?
It would make sense to be const because it is a simple getter that doesn't modify *this (syntactic const).
But on the other hand, it returns a non-const pointer to another object that it owns (semantically non-const).
If you make that non-const, then you cannot write this:
void f(const A & a)
{
auto v = a.GimmeLogger(); //error
}
So if you want to write this; that is, if you want to call GimmeLogger on const object, then make GimmeLogger a const member function, because you cannot invoke a non-const member function, on const object. However, you can invoke a const member function, on non-const object (as well as on const object).
Inside a const member function, every member is semantically const objects. So the type of m_logger in the function becomes const share_ptr<const m_logger>. So change the return type accordingly.
Because const is a keyword, it is checked syntactically, but it should be used semantically, that is, in your design operations that don't change the visible state of your class should be marked as const.
That is the whole idea behind the mutable keyword: adding the ability to mark a member as this does not take part of the visible state of the object so that the syntactic check matches the semantic meaning. In your particular case, because you are copying a pointer, you don't even need to use mutable there (this is one of the weak points of const-correctness actually, as returning a non-const pointer does not trigger errors while compiling, even though you are opening a door for changes in your object)
In this particular case, on the other hand, I don't see a good reason by which the object would publicize it's logger... That is, const-correctness aside, why do you need to grant access to the logger?
Yes, it should be const. The const-ness of the function has nothing to do with the const-ness of the return type.
I get your point, but I think the function remains const either way.
Generally you shouldn't return a handle to a member data when you can avoid it. Try hard to review your design and find a way around this. That said, if you must, it should be const. This allows you to call the function on const objects as well as non-const objects. See for example std::string::c_str(). You can also overload the function so you get both, like standard containers do with iterators.
When in doubt, look in the standard library for a hint.
Would it be possible for a public function to return a pointer to a private variable in the class. If so / if not, what would happen? would it crash or is there anything highly unsafe about this? Can the pointed data be read or written to?
Thanks
Yes, a member function may return a pointer (or reference) to a private data member. There is nothing wrong with this except that in most circumstances it breaks encapsulation.
The data member can certainly be read via the returned pointer or reference. Whether or not it can be written to depends on whether the returned pointer or reference is to a const-qualified object (i.e., if you return a const T*, you won't be able to modify the pointed-to T). For example:
class Example
{
public:
int* get() { return &i; }
const int* get_const() const { return &i; }
private:
int i;
};
int main()
{
Example e;
int* p = e.get();
int a = *p; // yes, we can read the data via the pointer
*p = 42; // yes, we can modify the data via the pointer
const int* cp = e.get_const();
int b = *cp; // yes, we can read the data via the pointer
*cp = 42; // error: pointer is to a const int
}
Yes it can be returned and it can be read and written to. It is no more or less dangerous than taking the address of any other variable. Public/private/protected are syntactical constructs that are checked at compile time, and they aren't "contagious" or part of the type of something.
A private member is no different from a public member, or any other type of instance. So, yes, you can take pointers to them, and return them.
When taking pointers to any instance-based member, you have to be careful that the parent class is not deleted and doesn't go out of scope, unless you take that pointer and make a true copy of the data/object it points to. If it is deleted or goes out of scope, the pointer becomes a dangling pointer, and you can't use it anymore without your app exploding (or working on non-existent objects, and thus making your program do crazy unexpected things, but not crashing).
Design considerations:
Exposing any of your internal implementation details is potentially a violation of encapsulation. However, if you only want to encapsulate HOW the object you're returning is created/retrieved, then this is a reasonable solution. This would allow you to change the class to get the member object some other way (like querying a file, or an internal dictionary) without breaking code that calls these methods.
"would it crash or is there anything highly unsafe about this? Can the pointed data be read or written to?"
private/protected/public have no effect whatsoever at runtime, so they can't influence the program execution or even crash the program. They are checked at compile time and just cause your compiler to throw an error while compiling if there is a violation.
The const qualifier won't protect you on those cases. Considering James's response, please try to cast the const int * to int *
int* cp = (int*)e.get_const();
You will still be able to modify.
Given the following code:
class foo;
foo* instance = NULL;
class foo
{
public:
explicit foo(int j)
: i(j)
{
instance = this;
}
void inc()
{
++i;
}
private:
int i;
};
Is the following using defined behavior?
const foo f(0);
int main()
{
instance->inc();
}
I'm asking because I'm using a class registry, and as I don't directly modify f it would be nice to make it const, but then later on f is modified indirectly by the registry.
EDIT: By defined behavior I mean: Is the object placed into some special memory location which can only be written to once? Read-only memory is out of the question, at least until constexpr of C++1x. Constant primitive types for instance, are (often) placed into read-only memory, and doing a const_cast on it may result in undefined behavior, for instance:
int main()
{
const int i = 42;
const_cast<int&>(i) = 0; // UB
}
Yes, it is undefined behavior, as per 7.1.5.1/4:
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.
Note that object's lifetime begins when the constructor call has completed (3.8/1).
This may be one of the rare cases where the not very known mutable keyword could be used:
mutable int i;
i can now be changed even if the object is const. It's used when logically the object doesn't change, but in reality it does.
For example:
class SomeClass
{
// ....
void DoSomething() { mMutex.lock(); ...; }
mutable Mutex mMutex;
}
In DoSomething() the object doesn't logically change and yet mMutex has to change in order to lock it. So it makes sense to make it mutable, otherwise no instance of SomeClass could be const (assuming you lock the muetx for every operation).
If you define a const instance of the object, then cast away the const-ness, and modify the contents of the object, you get undefined behavior.
From the sound of things, what you want is exactly the opposite: create a non-const instance of the object, then return a const pointer to that object to (most of) the clients, while the "owner" retains a non-const pointer to the object so it can modify members as it sees fit.
You'd typically manage a situation like this by defining the class with a private ctor, so most clients can't create objects of the type. The class will then declare the owner class as a friend, so it can use the private ctor and/or a static member function to create instances (or often only one instance) of the object. The owner class then passes out pointers (or references) to const objects for clients to use. You need neither a mutable member nor to cast away constness, because the owner, which has the "right" to modify the object, always has a non-const pointer (or, again, reference) to the object. Its clients receive only const pointers/references, preventing modification.
Calling a non-const (by declaration) member function on a const object is not illegal per se. You can use whatever method you wish to work around the compiler restrictions: either an explicit const_cast or a trick with constructor as in your example.
However, the behavior is only defined as long as the member function you are calling does not make an attempt to actually physically modify the object (i.e. modify a non-mutable member of the constant object). Once it makes an attempt to perform a modification, the behavior becomes undefined. In your case, method inc modifies the object, meaning that in your example the behavior is undefined.
Just calling the method, again, is perfectly legal.
It's hard to tell the intent with these arbitrary names. If i is intended as just a use counter, and it isn't really considered part of the data, then it is perfectly appropriate to declare it as mutable int i; Then the const-ness of an instance is not violated when i is modified. On the other hand, if i is meaningful data in the space being modeled, then that would be a very bad thing to do.
Separately from that, though, your example is a bit of a mess for what you seem to be asking. foo* instance = NULL; is effectively (if confusingly) using a NULL as a numeric zero and initializing instance, which is not const; then you separately initialize f, which is const, but never reference it.
Under GCC, at least, your constructor should be explicit foo(int j) with the word int.
However, it's perfectly fine to have two pointers to the same value, one const and the other not.
Why dont you make use of const cast ?
Any reason to make object as const eventhough its state is not constant?
Also make following change :
explicit foo(int j = 0) : i(j)
{ instance = this; }