VS2010 shows error C2440: 'return' : cannot convert from 'char *' to 'const char *&
in f3
below. Why is it not possible to return a char*
when the return type is const char*&
?
const char* const& f1()
{
static char* x = new char[5]();
return x;
}
char* const& f2()
{
static char* x = new char[5]();
return x;
}
const char* & f3()
{
static char* x = new char[5]();
return x; // error C2440
}
char* & f4()
{
static char* x = new char[5]();
return x;
}
From Paragraph 8.5.3/2 of the C++11 Standard:
A reference cannot be changed to refer to another object after initialization. Note that initialization of a reference is treated very differently from assignment to it. Argument passing (5.2.2) and function value return (6.6.3) are initializations.
This basically tells you that returning a value from a function is equivalent to performing an initialization. Therefore, function f3()
doesn't compile for the same reason the last initialization in the code snippet below doesn't compile:
char c = 'a';
char* x = &c;
const char*& y = x; // ERROR!
The type of the object referenced by y
is const char*
, while the type of the expression we are trying to initialize it with (i.e. the type of x
) is char*
. Those are different types, and when binding a reference the types of the initializer expression and of the object referenced by the initialized reference must be identical (with an exception for base and derived classes, which are not involved here), apart from top-level cv qualifications.
Here, the const
qualification in const char*
is not a top-level qualification, because it applies to the pointed object, and not to the pointer itself: while the pointed char
value cannot be modified through a const char*
pointer, the pointer itself can be reassigned.
In Standard terms, this means that the types const char*
and char*
are not reference-related:
Given types “
cv1 T1
” and “cv2 T2
,” “cv1 T1
” is reference-related to “cv2 T2
” ifT1
is the same type asT2
, orT1
is a base class ofT2
. “cv1 T1” is reference-compatible with “cv2 T2
” ifT1
is reference-related toT2
andcv1
is the same cv-qualification as, or greater cv-qualification than,cv2
. [...]
On the other hand, function f2()
compiles, consistently with the fact that the initialization in the last line below is legal:
char c = 'a';
char* x = &c;
char* const& y = x; // OK
Here, the type of the referenced object is char* const
, which (unlike const char*
) is reference-compatible with char*
in the sense defined by the Paragraph quoted above *(the const
qualification is a top-level qualification in this case).
In Particular, per 8.5.3/5:
A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:
— If the reference is an lvalue reference and the initializer expression
- is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or
[...]
The omitted part is not relevant to this case. Here, char* const
and char*
are reference-compatible, and the initialization is legal (and f2()
compiles). On the other hand, const char*
and char*
are not reference-compatible, and the initialization is illegal (and f3()
does not compile).
For the same reason you can't cast from char **
to const char **
. Otherwise you could write
f3() = "hello";
and a subsequent call to f3 would be able to write to the memory of the string literal, aliased to the static local x
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With