C++ function with const pointer parameter

77 Views Asked by At

I am learning about linked lists in my programming class right now. The following code is what compiles and works:

struct Node {
    int data;    
    Node *link;
   };

// this function compiles and works
size_t list_length(const Node* head_ptr) {
    size_t size{};
    for ( ; head_ptr != nullptr; head_ptr = head_ptr->link) {
        size++;    
    }
    return size;
}

The following implementation of the list_length function does not compile:

// this function gives a compile times error
size_t list_length(const Node* head_ptr) {
    size_t size{};
    Node *ptr = head_ptr;
    for ( ; ptr != nullptr; ptr = ptr->link) {
        size++;    
    }
    return size;
}

I am confused about the const qualifier. In this case, I know it means that the argument cannot be changed within the function. I have two questions:

  1. In the version of list_length that works, why can the for-loop change the value of head_ptr if head_ptr is a const variable? As the loop iterates, is it not changing the value of head_ptr?

  2. In the version of list_length that does not compile, why can I not assign the value of head_ptr to new pointer variable?

3

There are 3 best solutions below

2
OldBoy On

In the second case you are trying to create a pointer to a non-const Node from a pointer to const one. The compiler will not allow this as it may cause problems elsewhere. You can either use a pointer to a const Node for the copy, or use const_cast to bypass the error check. So either:

const Node *ptr = head_ptr; // make ptr to const to match the source item

or

Node *ptr = const_cast<Node*>(head_ptr); // cast away the const

In case 2 here, the compiler allows the cast as you are telling it that you know what you are doing.

0
JamieNguyen On

1. In the version of list_length that works, why can the for-loop change the value of head_ptr if head_ptr is a const variable? As the loop iterates, is it not changing the value of head_ptr?

head_ptr is a pointer to a variable of datatype "const Node". Therefore head_ptr is not a constant, yes, it is just a normal pointer. So you can just change it freely as you wish.

2. In the version of list_length that does not compile, why can I not assign the value of head_ptr to new pointer variable?

Because head_ptr is a pointer to a variable of datatype "const Node", and ptr is presumably a pointer to a variable of datatype "Node", so this is a mismatch.

Reference: const (C++)

0
Chris Uzdavinis On

I am confused about the const qualifier. In this case, I know it means that the argument cannot be changed within the function.

What you are describing as what you know is actually slightly off. In this code, the argument is a non-const pointer to a const Node object. The argument can change, but the thing it points to cannot.

const affects the thing to its left... UNLESS there's nothing to its left, and then it affect the thing to its right. (This means you can read the type right-to-left correctly: Node const * head_ptr means "head_ptr is a (non-const) pointer to a const Node"

What you are describing is a different thing, a const pointer to a non-const node, and that would look like this: Node * const head_ptr ("head_ptr is a const pointer to a (non-const) Node")

I have two questions: In the version of list_length that works, why can the for-loop change the value of head_ptr if head_ptr is a const variable? As the loop iterates, is it not changing the value of head_ptr?

head_ptr is not const. The thing it points to is const. Modifying head_ptr is perfectly fine.

In the version of list_length that does not compile, why can I not assign the value of head_ptr to new pointer variable?

It's attempting to convert a pointer-to-const-Node to a pointer-to-Node. Such a conversion is unsafe, because if you start with something that could not be modified, but it was allowed to make such a conversion, then you could too easily bypass the const-ness by simply looking at the pointer differently. C++ requires you to be more forceful to remove const, since doing it incorrectly can result in undefined behavior if you end up modifying an object that actually was declared const (as opposed to gaining const qualification later.)