Question

I have two getter members:

Node* prev() { return prev_; }
int value()  { return value_ }

Please note the lack of const identifiers (I forgot them, but now I want to know why this won't work). I am trying to get this to compile:

Node(Node const& other) : prev_(other.prev()), value_(other.value()) { }

The compiler rejects this. I thought that C++ allows non-const to const conversion in function parameters, such as:

{
   Foo(int bar);
}

Foo(const int bar)
{
   //lala
}

Why won't it let me do the same thing with a copy constructor? The const identifier means I promise not to change anything, so why would it matter if I get my value from a const or non-const source?

Was it helpful?

Solution

You're not trying to do a non-const to const conversion. You're attempting to call two methods which are not const an a const reference (calls to prev and value). This type of operation is strictly forbidden by const semantics.

What you could do instead is use the fields prev_ and value_ directly. Because it's a member of the same type you can access privates which will be available on the const object.

OTHER TIPS

I thought that C++ allows non-const to const conversion in function parameters, such as:

You are trying to do the exact opposite: Const to non-const. Calling a non-const member function, the compiler will bind the expression (which is a Node const to a Node& for binding the this pointer). It thus will drop const - not allowed because it would call a non-const function on a const object.

/* class Foo */ {
   Foo(int bar);
}

/* Foo:: */ Foo(const int bar)
{
   //lala
}

Well that code is a whole other thing. It declares a function (constructor) two times, with the only difference being that one time the parameter is const, and another time it isn't. The type of the function is the same both times, and so they don't conflict (the const parameter will only have an impact within the function body locally - it won't make any difference to the caller). In addition, this code doesn't contain any call (assuming that the first block is within some function).

If you wonder: If the above two versions are identical - why isn't the below? Then this is because the below contains one other level of indirection: Below, the reference itself (the top level) is not const (you can't put const on a reference itself directly), but the type referenced is const. At this time, const is not ignored in determining the type of the function.

/* class Foo */ {
   Foo(int &bar);
}

// different thing, won't work!
/* Foo:: */ Foo(const int &bar)
{
   //lala
}

You're right - the const means you promise not to change anything. The compiler is making you keep your promise by not allowing you to call methods on that object which do not themselves promise not to change anything.

In the declaration of the constructor Node(Node const& other) the argument other is declared const. This means you can only call const methods on it.

You are calling other.prev() and other.value() from the constructor both of which are non-const methods, hence the compiler complains.

As others have mentioned, you're calling non-const methods on a const object which the compiler will not allow.

A simple fix for this is to just mark your getter functions as const:

Node* prev() const { return prev_; }
int value()  const { return value_; }

since they don't modify the object; now they can be called with a const object. In fact, this should probably be done anyway so that users of the class can call those getters with const objects.

However, you have another potential problem in that if your copy ctor looks like:

Node(Node const& other) : prev_(other.prev()), value_(other.value()) { }

the copy and the original will both point to the same Node object in their prev_ member. Depending on the class semantics this might be OK, but it might be an ownership issue or other logical inconsistency.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top