Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent accidentally calling a mutating function on a non-const object?

Tags:

c++

c++11

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?

like image 749
ForeverStudent Avatar asked Dec 04 '15 21:12

ForeverStudent


People also ask

What will happen if a const object calls a non const member function?

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.

How important is const correctness?

The benefit of const correctness is that it prevents you from inadvertently modifying something you didn't expect would be modified.

When should a method be const?

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.

What is a situation in which returning a const value is good idea?

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.


2 Answers

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.

like image 196
T.C. Avatar answered Sep 22 '22 01:09

T.C.


Foo(static_cast<const myType&>(obj)); 
like image 21
Brian Bi Avatar answered Sep 22 '22 01:09

Brian Bi