2

I was trying to understand the use of 'const' keyword with pointers from the source: GeeksforGeeks. It is mentioned that "Passing const argument value to a non-const parameter of a function isn't valid it gives you a compile-time error." However, *ptr, where ptr is a pointer to a constant value, did not raise an error when passed as an argument to a non-const parameter of a function.

In the following code:

#include <iostream>
using namespace std;

int content_of(int* y) { return *y; }

int same(int k){return k;}
// Functions with non-const parameters

int main()
{
   int z = 8; //Non-const integer
   const int *x = &z; //Pointer to constant
   return 0;
}

When I pass 'x' as an argument in 'content_of':

cout << content_of(x)<<'\n';

It raises an error:

argument of type "const int *" is incompatible with parameter of type "int *"

This can be resolved by replacing int* y with const int* y. Passing &z (address of z), on the other hand, is valid as it is non-const. This agrees with the theory above.

But, when I pass *x into the function same:

cout << same(*x)<<'\n';

It gives output 8, raising no errors. Passing z, too, gave the same output and raised no errors, as expected.

It was my understanding that *x was of type const int (because, unlike z, I was not able to reassign a different value to it). Hence, it should have raised an error on being equated to a non-const int k. Why is that not the case?

5
  • 6
    GeeksforGeeks is a poor resource for learning C++. I recommend a good C++ book instead. Commented Jun 15 at 20:12
  • 1
    Please invest in some decent beginners material, that teaches you the semantics of passing an argument by value. Commented Jun 15 at 20:42
  • This is the reverse situation as in const parameter, but this answer can be readily applied to your situation. Also related: Does using const on function parameters have any effect? Why does it not affect the function signature? Commented Jun 15 at 21:36
  • It is always important to learn from a "good enough" source : e.g. learncpp.com, and look at examples from cppreference.com. Later read the C++ core guidelines, I say later because it is the goto source on how to use C++ now, but it requires a bit of understanding of C++ first (though if you read it now, anything not clear to you yet is a good thing to learn about) Commented Jun 16 at 5:07
  • @Nehal Does any of the answers you've gotten answer your question? If you'd like any of us to clarify our answers, please just ask. Commented Jun 27 at 9:17

2 Answers 2

6

*x dereferences x and you get a const int&. You could not bind a non-const reference to it:

int same(int& k){...} // non-const ref
same(*x);             // compilation error

You can however copy the value from a const instance to a non-const instance, which is what is happening here. It's similar to:

const int x = 123;
int y = x;         // no problem
Sign up to request clarification or add additional context in comments.

Comments

3

The main difference between the two functions is that:

  • content_of() takes an int* argument, which means that it is allowed to change the content pointed to and might very well do so. You know that's not the case, but imagine that you'd only have the function declaration and the function would be written by someone else in another compilation unit...
    With only the function declaration, you'd have no guarantee that constness would be respected. Therefore, your compiler flags the risk of passing a const int* : the compiler knows the content must not be modified and notices you pass it to a function which could infringe this constraint.
    The only way to tell the compiler that content_of() would never change the content pointed to, is to make its argument const int*. By the way, you could very well pass an int* for a const int* parameter, because there's no risk.
  • same() takes an int argument, which means it passes the argument by value. There is hence no risk that the original content pointed to would be modified. The function does not have the slightest clue that a pointer was used to evaluate its argument! Therefore, whether you dereference a pointer or a pointer to const makes no difference at all. This is why you don't get any error message.

As a rule of thumb, whenever you define a function taking a reference or a pointer as argument, if you know it's content is not supposed to change, make this knowledge explicit in the code with a const argument.

Here the revised code with some more explanations in the comments :

#include <iostream>
using namespace std;

int content_of(const int* y)   // we garantee that pointed content will never be changed
{ 
    //if (*y=true)  // ooops ! Not even risk of an accidental type overwriting: compiler would flag it 
    //    ...
    return *y; 
    
}

int same(int k)     // we pass by value.  The original content will never ever be changed
{
    //if (k=true)  // ooops ! Typo would produce wrong return value but not change original content
    //    ... 
    return k;
}

int main()
{
   int z = 8;           //Non-const integer
   const int *x = &z;       //Pointer to const: z shall not be altered via this pointer 
   int*xx = &z;             
   
   cout << content_of(x)<<endl;   // sno risks, no error
   cout << content_of(xx)<<endl;  // pointer to non const can be used: no pb if we promise not to change it
   cout << same(*x)<<'\n';        // no risk either, no error
   
   return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.