4

I have some code which has been written without regard for const correctness. Are there any circumstances in which changing this

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

to this

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

would change the behaviour of an existing program? I know this change will allow code which doesn't currently compile to compile, but I'm interested if there is any circumstance in which code that already compiles would change it's behaviour.

Similar question, is there any merit in making this change instead?

class X
{
public:
    X(X& rhs); // does not modify rhs
    X(const X& rhs);
    ...
};
john
  • 7,897
  • 29
  • 27
  • I can see that my question has been slightly misinterpreted. I'm not asking how to rewrite the copy constructor, my question was whether there is any danger in doing given the very large amount of code using class X. This code was written by someone who clearly had no idea about const and was using a compiler which didn't care. Now in porting to a new compiler I'm left with code that doesn't compile and with classes I cannot use in the STL. – john Apr 22 '13 at 17:15

4 Answers4

2

For copy constructor I don't think so. But note that in general, yes, declaration of const can affect which method is called. The only example that comes to mind is with array overloading - see e.g. this question.

Community
  • 1
  • 1
djechlin
  • 59,258
  • 35
  • 162
  • 290
1

In fact a copy constructor should, imho, always take a const reference as its argument.

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

This does not allow to copy const objects and hence the following code will not compile. While non-const objects can serve as const arguments, the other way round is impossible

X const test;
X new_x(test);

I can't imagine why someone should preclude the copy of a const object.

Concerning the changes you want to make: Does the copy constructor rely on any X member function that is defined non-const?

This will work like a charm but permit copying const objects:

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

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

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

If you want to make your class const correct you'll probably have to examine the whole class. It should only affect your in-class-implementations. Since I don't know a case where external code should rely on "non-constness" of a class member function. Except when non-const-references are returned by any public member-functions as in my example.

The following snippet will do 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 be aware that this will interfere with any code like:

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

This would work using int& value (void) { return a; } but fails with int const & value (void) const { return a; }. You could of course provide both to be on the safe side.

Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
0

Since you are changing the class that has the copy constructor I am assuming you can inspect the copy constructors code. If you can make this change and the copy constructor does not give a compiler error you are probably good. One conor case to consider is what the copy assignment operator does as there is no assurance which will be called especially in optimized code. So also make sure that your copy assignment will work with a const parameter.

rerun
  • 25,014
  • 6
  • 48
  • 78
  • 1
    Can you give an example where you cannot be certain whether copy constructor or assignment operator will be called? – Agentlien Apr 22 '13 at 12:46
  • This came fro a question I asked on eliding. http://stackoverflow.com/questions/9267687/understanding-eliding-rules-with-regard-to-c11 – rerun Apr 22 '13 at 12:48
  • As far as I can see, this only means you cannot determine whether copies will be elided or not. Regardless, I don't see a case where you the assignment operator would be called when you (have reason to) expect the copy constructor, or vice versa. – Agentlien Apr 22 '13 at 12:52
0

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

The constness of an object or reference affects overload resolution. For instance, if you have an object with a const based overload of a member function, different overloads will be chosen:

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 the other doesn't, you'd get different behavior after changing the signature, given that (or rather even though) the program compiles fine.

Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283