Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Would it make sense to have a 'constify' operation in C++?

Would it make sense to have a "constify" operation in C/C++ that makes a variable const?

Here is an example where it could be useful, where obviously we don't want to declare it const yet in the first line:

std::vector<int> v;
v.push_back(5);
constify v; // now it's const

Currently, without such a possibility, you'd have to introduce another variable to get the same effect:

std::vector<int> v0;
v0.push_back(5);
const std::vector<int>& v = v0;

That's more confusing since it adds a new name into the scope and you need to make it a reference to avoid copying the whole vector (or use swap?).

like image 802
Frank Avatar asked Aug 25 '10 16:08

Frank


People also ask

Does using const improve performance?

const correctness can't improve performance because const_cast and mutable are in the language, and allow code to conformingly break the rules. This gets even worse in C++11, where your const data may e.g. be a pointer to a std::atomic , meaning the compiler has to respect changes made by other threads.

Why is const correctness important?

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

How do you declare a variable constant after declaration?

Variables can be declared as constants by using the “const” keyword before the datatype of the variable. The constant variables can be initialized once only. The default value of constant variables are zero.

What does const& mean in C++?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.


1 Answers

Frankly, I find it less confusing if a variable is either const or not, than if this can change.


To elaborate a bit on this: The reason you usually want to do this is because you cannot initialize a const variable the way you want to. std::vector is a good example of this. Well, for once, the next standard introduces a universal initialization syntax that makes this possible:

const std::vector<int> cvi = { 1, 2, 3, 4, 5, 42 }; 

However, even without C++1x' stuff at hand, and even with types that disallow this initialization syntax, you can always create a helper function to do what you want:

const std::vector<int>& cvi = create_my_vector();

or, if you want to be fancy:

const std::vector<int>& cvi = compile_time_list<1,2,3,4,5,42>::create_vector();

Note the &. There's no point in copying the result of the function call, since binding an rvalue to a const reference extends its lifetime until the end of the reference's lifetime.
Of course, recompiling with a compiler that supports C++1x' move semantics will render such optimizations pretty much needless. But binding an rvlaue to a const reference might still be faster than moving a vector and is unlikely to be slower.
With C++1x, you might also create lambda functions doing this one the fly. C++ just provides an incredibly huge arsenal of tools. IME, no matter how hard you have thought, someone else ought to come up with yet another idea to do the same thing. And often a better one than yours.


However, IME this problem usually only comes with too much code in too few functions anyway. And then it doesn't only apply to constness, but also to similar traits - like what a reference refers to.
A classic is the use-one-of-several-possible-streams. Instead of this

int main(int argc, char* argv[])
{
  std::istream* istrm = NULL;
  std::ifstream ifs;
  if( argc > 1 )
  {
    ifs.open( argv[1] );
    if( ifs.good() ) 
      istrm = &ifs;
  }
  if( !istrm ) 
    istrm = &std::cin;

  while( istrm->good() )
  {
     // reading from *istrm implemented here
  }
  return 0;
}

just split the concerns into 1) figuring out where to read from and 2) the actual reading:

int read(std::istream& is)
{
  while( is.good() )
  {
     // reading from is implemented here
  }
  return 0;
}

int main(int argc, char* argv[])
{
  if( argc > 1 )
  {
    std::ifstream ifs( argv[1] );
    if( ifs.good() ) 
      return read(ifs);
  }
  return read(std::cin);
}

I have yet to see a real-world example of a variable that wasn't as constant as it could have been which couldn't be fixed by separating of concerns.

like image 84
sbi Avatar answered Sep 20 '22 23:09

sbi