Adding Constant Correctness

I have a code that was written without regard to constant correctness. Are there any circumstances under which a change in this

class X { public: X(X& rhs); // does not modify rhs ... }; 

to that

 class X { public: X(const X& rhs); ... }; 

will change the behavior of an existing program? I know that this change will allow the use of code that is not currently compiling, but I am wondering if there are any circumstances in which code that is already compiling will change its behavior.

A similar question, is there any merit in this change?

 class X { public: X(X& rhs); // does not modify rhs X(const X& rhs); ... }; 
+4
source share
4 answers

For the copy constructor, I don't think so. But keep in mind that in the general case, yes, a const declaration can affect which method is invoked. The only example that comes to mind is array overloading - see, for example, this question .

+2
source

In fact, the copy constructor should, imho, always accept a const reference as an argument.

 X(X& rhs) { } // does not modify rhs 

This does not allow const objects to be copied and, therefore, the following code will not compile. Although objects that are not constants can serve as arguments to const, it is impossible to avoid another way.

 X const test; X new_x(test); 

I cannot imagine why anyone should exclude a copy of the const object.

Regarding the changes you want to make: Is the copy constructor relying on any X-member function that is not defined by const?

This will work like a charm, but allow copying const objects:

 class X { private: int a; public: X(X &rhs) { a = rhs.value(); } int& value (void) { return a; } }; 

The following example will not compile since rhs is const, but value() not const.

 class X { private: int a; public: X(X const &rhs) { a = rhs.value(); } int& value (void) { return a; } }; 

If you want your const class to be correct, you probably have to examine the whole class. This should only affect the implementation within the class. Since I do not know the case when external code must rely on the "non-constant" function of a member of the class. Unless non-const links are returned by any public member functions, as in my example.

The following snippet will work as intended.

 class X { private: int a; public: X(int const &b) : a(b) { } X(X const &rhs) { a = rhs.value(); } int const & value (void) const { return a; } }; 

But keep in mind that this will affect any code:

 X test(100); test.value() = 12; 

This will work using int& value (void) { return a; } int& value (void) { return a; } , but not with int const & value (void) const { return a; } int const & value (void) const { return a; } . Of course, you could both be safe.

+1
source

Since you are changing the class with the copy constructor, I assume that you can check the copy constructor code. If you can make this change and the copy constructor will not give a compiler error, you are probably good. One case of conor to consider is what the copy assignment operator does, since there is no certainty that will be invoked especially in optimized code. Therefore, also make sure that your copy assignment will work with the const parameter.

0
source

djechlin makes an important point in his answer , although it is somewhat unclear, so I will try to explain better.

The stability of an object or link affects overload resolution. For example, if you have an object with an overloaded const function for a member function, different overloads will be selected:

 struct foo { void do_stuff(); void do_stuff() const; }; int main() { foo f; const foo& fr = f; f.do_stuff(); // calls non-const version fr.do_stuff(); // calls const version } 

Now, if one of the overloads has side effects, and the other does not, after changing the signature you will get a different behavior, given that the program (or rather, though) is compiled by the program.

0
source

All Articles