Suppose we have an Object obj of type myType, and we would like to pass it to function Foo, which returns us some valuable information about obj. function Bar is where obj is declared and from which Foo is being called like this:
void Bar () { myType obj; //default constructor string valuableInfo = Foo(obj); //do other stuff //... } //end of Bar()
This snippet of code of course does not say much about whether Foo takes obj as a reference or as value, and whether or not Foo modifies obj in any way.
of course if Foo takes obj as value or const reference, we wont have any issues.
string Foo (const myType & input); //this is fine string Foo (myType input); //so is this
but we are not guaranteed this! the function signature could very well be
string Foo (myType & input); //asking for trouble!!
but it is awfully inconvenient to check the signature of every function we would want to pass obj to, so how can we specify that we want to only pass our object to functions that promise not to modify it?
of course one approach is to declare obj as const, but the problem with this approach is that we lose flexibility. what if we want to modify obj in Bar() after calling Foo(obj)?
void Bar () { const myType obj; //default constructor string valuableInfo = Foo(obj); //compiler will complain if Foo's signature doesnt match //we can't modify obj here :( //... } //end of Bar()
The obvious but bad solution is to do this:
void Bar () { myType obj; //default constructor const myType immutableObj {obj}; //copy ctr call //this is expensive and not recommended if obj is big! want to avoid string valuableInfo = Foo(immutableObj); //will get the valuable Info risk free // compiler will complain if Foo has inappropriate signature //do other stuff //... } //end of Bar()
so What is the best solution here? is there a way to statically assert that Foo is non invasive to the object we pass in? can we temporarily make obj const (without having to create a new const object) or something to that effect?
If the function is non-constant, then the function is allowed to change values of the object on which it is being called. So the compiler doesn't allow to create this chance and prevent you to call a non-constant function on a constant object, as constant object means you cannot change anything of it anymore.
The benefit of const correctness is that it prevents you from inadvertently modifying something you didn't expect would be modified.
A function becomes const when the const keyword is used in the function's declaration. The idea of const functions is not to allow them to modify the object on which they are called. It is recommended the practice to make as many functions const as possible so that accidental changes to objects are avoided.
In the hypothetical situation where you could perform a potentially expensive non-const operation on an object, returning by const-value prevents you from accidentally calling this operation on a temporary.
In C++17, thanks to P0007R1:
foo(std::as_const(obj));
Before C++17, if you find yourself needing to do this often, writing a helper yourself is trivial:
template<class T> constexpr typename std::add_const<T>::type& as_const(T& t) noexcept { return t; } // prevent accidentally creating an lvalue out of a const rvalue template<class T> void as_const(const T&&) = delete;
Of course, nothing you do can protect against someone deliberately casting away constness. Murphy, Machiavelli, etc.
Foo(static_cast<const myType&>(obj));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With