Why does const reference to string parameter accept string literals?
Why does a const reference to a string parameter accept string literals? String literals like "hello"
are not variables, so why is this code valid?
class CVector {
public:
int x, y;
CVector() {};
~CVector() { delete ptr; }
string* ptr;
void doSomething(const string& str) { ptr = new string(str); }
void print() { cout << "\n" << *ptr; }
};
int main()
{
result.doSomething("asdas");
result.print();
return 0;
}
First of all, I thought that references as parameters were used to avoid the copying process and to directly access the variable taken as an argument (I may still be right, though). But the string literal "asdas" is not a variable, so why can the parameter accept string literals as an argument? I mean, since the parameter str
is a reference, it will become an alias for that object, right? If so, did literal just become a variable?
Shouldn't the parameter list consist of string& str
instead of a constant reference for the literal to be used in construction str
?
And doesn't the constant maintain a reference to the referenced object until the reference is saved? If so, why are you doing this in literature?
When you do
result.doSomething("asdas");
The compiler looks to see if you have one doSomething(const char[]);
and finds nothing. Since there is no matching function, it tries to find an overload that takes what can be built from const char[]
and finds it doSomething(const string& str)
. Since the compiler is allowed to do one custom conversion, it creates a temporary std::string
from the string literal and passes that temporary reference via const to the function.
Shouldn't the parameter list consist of the string & str instead of a const reference, so that the literal will be used when constructing str?
No, this only works with a const reference and will not work with a regular reference, since regular references cannot bind to temporary ones.
And doesn't the constant maintain a reference to the referenced object until the reference is saved? If so, why are you doing this in literature?
A const reference will only extend the lifetime of an object if it is a local function object. Inside the function, the function will be alive since the expression that called this function did not end, but if you try to store the reference to std::string
in the class that will not work.
Efficiently the code is converted to
int main()
{
CVector result
{
std::string temp = "asdas";
result.doSomething(temp);
}
result.print();
return 0;
}
source to share
String literals like "hello" are not variables
The term "variables" is rather vaguely defined and not supported by any specific concepts.
The expression "hello"
represents an object with a static storage time that you cannot modify. Like any other expression, it can be used to initialize some other object. In this case, you initialize with an std::string
expression (after it decays to const char*
).
What you are missing is a "middle step", constructing a temporary std::string
from this literal, whose lifetime is then extended by binding to ref-to- const
.
So ish:
const std::string temp{"Hello world"}; // the compiler creates this transparently
const std::string& ref = temp; // this is yours, and it extends temp life
Learn about implicit conversions for more information.
source to share
std::string
has an implicit conversion constructor const char *
.
The compiler is allowed to do one implicit conversion to match the types, so it uses said ctor to temporarily convert const char *
to std::string
, and it moves smoothly from there, since const&
(constant l references) are allowed to bind to temporary (and extend their lifetime).
source to share