Confusion about return type of a function when it is a pointer

Viewed 122

I wrote the following code:

#include <iostream>
using namespace std;

const int * myFunction()
{
    int * p = new int(5);
    return p;
}
 
int main()
{
    int * q = myFunction();
    cout << "*q=" << *q;
    cout << endl;
    return 0;
}

I purposely wrote the above code to receive an error. The mistake I made is that I stated the return type of function myFunction() as const int * but when I called myFunction() in main(), the pointer variable q was not declared const. The return type of myFunction() must match exactly to the type of variable which is going to receive its return value (am I correct here? This is what I have understood).

So, I fixed the error by correcting line 11 as const int * q = myFunction();. Now the type of the (pointer)variable q, which is const int *, matched exactly to the return type of myFunction() and the code compiled without error, producing output as *q=5 (is my understanding up to this point correct?).

Then, I wrote the following code:

#include <iostream>
using namespace std;

const int * const myFunction()
{
    int * p = new int(5);
    cout << "p: " << p;
    return p;
}
 
int main()
{
    int a;
    const int * q = myFunction();
    cout << "\nq=" << q;
    cout << "\n*q=" << *q;
    delete q;
    q = &a;
    cout << "\nq: " << q;
    cout << endl;
    return 0;
}

I was expecting an error here, too. Because now the return type of myFunction() is const int * const but the (pointer)variable q had type const int *. q was not declared as a constant pointer. But the program compiled and I got output as follows:

p: 0x36cb8
q=0x36cb8
*q=5
q: 0x61ff08

I am confused why the second code compiles and runs. What I thought is whoever is going to receive the return value from myFunction() should always take care of it (i.e. it cannot be allowed to take a different memory address), but the pointer variable q took a different memory location.

2 Answers

The return type of myFunction must match exactly to the type of variable which is going the receive it's return value. (Am I correct here? This is what I have understood.)

No, the return type must not match exactly to the type of the variable. But it must be possible to implicitly convert the return type to the type of the variable. For example something like this will compile:

int someInt = getMeAFloat();

If getMeAFloat returns a float, this will compile because a float can be implicitly converted to an int. (Note that this gives you a warning and is bad because you lose the extra information of the float, but I am just trying to bring my point across)

Your first example does not compile because normally a const int* can not be converted to a int*.

As pointed out by user4581301 the second const in your second example does not matter, because only the value of the pointer, which is returned, gets assigned to the pointer in the main function. The second const makes the pointer itself constant, which has no effect on the value. That means that const int * const myFunction() is equal to const int * myFunction()

In the 2nd code, q is a const int * - a non-const "pointer to a const int". Since q itself is not const, it can be re-assigned to point at a new address.

The compiler allows q = &a; because an int* (ie, what &a returns since a is an int) can be assigned to a const int*. In other words, a "pointer to non-const data" can be assigned to a "pointer to const data", effectively making read-only access to otherwise-writable data.

The reverse is not true - a "pointer to const data" cannot be assigned to a "pointer to non-const data", as that would allow writable access to read-only data - which is why the 1st code fails to compile.

Related