9

I thought the concept of "const-correctness" was pretty well defined, but when I talked to other people about it, it seemed we had different ideas of what it means. Some people say it's about a program having the "const" annotations in as many places as possible. Others define a program as const-correct if and only if there are no violations of constness where the const annotation is used (ie. it's a property that the compiler checks for you).

So I'd like to know, which of these functions are const correct:

struct Person {
    string getName1() const { return _name; }
    string getName2() { return _name; }
    string getName3() const { _name = "John"; return _name; }
    string getName4() { _name = "John"; return _name; }

    string _name;
};

I've searched on the Internet for definitions but couldn't really find definite answer, and I also have suspicions that there might be a case of citogenesis at play. So could anyone provide any solid citation for a definition?

exclipy
  • 1,423
  • 1
  • 15
  • 21
  • getName3 won't compile, so skip that. – Tommy Andersen Nov 26 '11 at 10:33
  • [What is "const correctness"?](http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.1) – cpx Nov 26 '11 at 10:38
  • http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier – Flexo Nov 26 '11 at 10:45
  • Everyone, please note the last part of the question about providing a solid source. Some guy's webpage doesn't really count in my mind (even if it's Marshall Cline). – exclipy Nov 26 '11 at 10:56
  • @exclipy - The standard defines what `const` means, "const correctness" is a coding convention that makes effective use of it. – Flexo Nov 26 '11 at 11:02
  • 5
    @exclipy: Marshall Cline's website isn't a mere C++ enthusiast's site. It hosts the official C++ FAQ, as assembled by the regulars of the `comp.lang.c++.moderated` Usenet discussion group, sine a long time (decades, really) _the_ reliable source if you wanted to know something about C++, and the place where you might find the authors of the books on your shelf (including, but not limited to, Bjarne Stroustrup) answering your questions. I'd count that as a source much more definitive than Stackoverflow. – sbi Nov 26 '11 at 11:52
  • you're missing `const std::string& getName5() const { return _name; }` :] – stijn Nov 26 '11 at 12:05
  • In my personal opinion: `const` is a virus (arising from the need for const references), a piece of code is `const` correct if it remains compilable when exposed to the virus (often meaning it helps to spread the virus). - For example, `getName2` is not const correct, because the const virus will bring it down when you get a valid desire to get the name from a const Person. – UncleBens Nov 26 '11 at 12:28

6 Answers6

10

In my view "const correctness" means:

Everything that isn't intended to be modified should be marked as const.

This means that the compiler can tell you when you make a mistake. (It also possibly has implications for optimisations in certain conditions, but that's more of a secondary benefit and depends on a lot of other factors)

There are three basic places where this is useful:

  1. Member functions can be marked const, as in your examples. This means that your accesses to member variables from within that function will be as though the variables themselves were const. (This is the example you've shown, although getName3() won't work)

  2. "Free" variables, local and member variables themselves may also be marked const - once initialised they may not be changed. Example - local variable:

    int f(int i) {
       const int square = i*i;
       // do something here that uses, but doesn't change square
       return square;
    }
    

    Or free variable:

    extern const double PI; // set somewhere else but not changed.
    

    Or member variable:

    class foo {
       const int state; // can't be changed once constructed
       foo(int s) : state(i) {}
    };
    
  3. Function arguments can also be marked const, the definition can match a non-const declaration still:

    void f(int i);
    void f(const int i) {
        // the fact that i is const is an implementation detail of f here
    }
    

    As a side note const correctness for references is required in some cases:

    void g(const std::string& s);
    void f(std::string& s);
    

    Of these two one can be used in more places:

    g("hi"); // Fine
    f("hi"); // Not fine - you can't bind a temporary to a reference
    

    Of course if you meant to change s then passing a temporary in makes little sense anyway.

Flexo
  • 87,323
  • 22
  • 191
  • 272
4

Text from parashift:

It means using the keyword const to prevent const objects from getting mutated.

KV Prajapati
  • 93,659
  • 19
  • 148
  • 186
1

Only getName3 violates const-correctness, because _name is constant (specifically, it is const std::string &) in the function body, and std::string::operator= is not const.

getName2 is poor design because it requires a mutable context even though it doesn't perform any mutations, so it should be declared const, as it would otherwise lead to surprising restrictions, i.e. you cannot call it through a const Person &.

You might also add "volatile" and "rvalue" correctness into the mix, which are similar in spirit.

Const-correctness can be felt through its non-local effects. Typical examples are relational operators (operator< and operator==): If you fail to mark them as const, many standard algorithms and containers won't work with your class, as they will usually apply the operators to constant element references. In that sense, not being "as const as possible" puts unnecessary restrictions on the use of your code. From the opposite view, the same applies if your own functions unnecessarily require a mutable reference to an object, as this will preclude you needlessly from using constant references and deprive you of compile-time checks that the operation you thought was non-mutating did in fact not mutate the object.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

This faq chapter talks only about const correctness for c++. To quote it :

It means using the keyword const to prevent const objects from getting mutated.

About your member functions:

string getName1() const { return _name; }

This one const-correct. It just returns copy of a member variable.

string getName2() { return _name; }

This one is not const-correct, because it is not declared const member.

string getName3() const { _name = "John"; return _name; }

Not const-correct, because it modifies a member variable in const member function. It should produce a compilation error.

string getName4() { _name = "John"; return _name; }

It is const-correct, because it modifies a member variable.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
0

Const correctness is correctly identifying and specifying cases where methods are either mutable or immutable.

Anything that isn't mutable should be marked const.

Read more on wikipedia

Tommy Andersen
  • 7,165
  • 1
  • 31
  • 50
0

getName3() is incorrect, because it changes name. The others are correct.

Specifying a method constant is sometimes inhandy and sometimes required. When I have finished coding my projects, I check which methods can be made constant to improve readability of my code. While still coding, I don't specify methods constant a lot, because it is obstructing the progress of the work. For the same reason, I declare all members public until I have finished the coding and then I apply private and protected whenever applicable.

bert-jan
  • 958
  • 4
  • 15