11

Why can a const reference to a string parameter take 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 directly access the variable taken as argument(I could still be correct though). But the string literal "asdas" is not a variable, so why can the parameter take string literals as argument? I mean since the parameter str is a reference, it will become an alias for that entity, right? If so, did the literal just become a variable?

Shouldn't the parameter list consist of string& str instead of the const reference, so that the literal would be used in the construction of str?

And doesn't a const reference keep the referenced entity alive for as long as the reference is alive? If so, why would you do that to a literal?

1
  • simply put, there is a conversion(i.e. ctor) that takes string literal and creates string instance. Commented May 22, 2017 at 19:13

3 Answers 3

11

When you do

result.doSomething("asdas");

The compiler looks to see if you have a doSomething(const char[]); and finds nothing. Since there is not suitable function it then tries to find an overload that takes something that can be constructed from a const char[] and it finds doSomething(const string& str). Since the compiler is allowed to make one user defined conversion it constructs a temporary std::string from the string literal and pass that temporary, via reference to const, to the function.

Shouldn't the parameter list consist of string& str instead of the const reference, so that the literal would be used in the construction of str?

No, this only works with a reference to const and will not work with a regular reference as regular references cannot bind to temporaries.

And doesn't a const reference keep the referenced entity alive for as long as the reference is alive? If so, why would you do that to a literal?

The reference to const will extend the lifetime of the object only when it is a function local object. Inside the scope of the function the object will be alive as the expression that called that function has not ended but if you were to try and keep a reference to the std::string in the class that would not work.

Effectively you code is translated into

int main()
{
    CVector result
    {
        std::string temp = "asdas";
        result.doSomething(temp);
    }
    result.print();
    return 0;
}
Sign up to request clarification or add additional context in comments.

10 Comments

Note that the object being passed into the function is the temporary string that was constructed, not the literal itself.
result.result.doSomething("asdas");("asdas"); doesn't look right
Thanks. But so it the parameter const string& str) a reference the the literal "asdas" itself or another string created from that literal?
@JakeBlandon It lives for until the end of the expression. That is to say that it will be destroyed after doSomething returns and before the call to print
@JakeBlandon They are scoped to the full expression that created them. When the expression ends the temporary is destroyed. Generally a full expression is something that ends with a ;. As far as further resources I don't have any except for the books/references from here: stackoverflow.com/questions/388242/…
|
4

String literals, like "hello", are not variables

The term "variables" is pretty vaguely defined, and not really backed up by any concrete concepts.

The expression "hello" represents an object with static storage duration that you cannot modify. Like any other expression, it may potentially be used to initialise some other object. In this case, you're initialising a std::string with the expression (after its decay to a const char*).

What you're missing is the "middle step", the construction of a temporary std::string from that literal, whose lifetime is then extended via the binding to a 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's life

Read about implicit conversions for more information.

Comments

1

std::string has an implicit const char * converting constructor.

The compiler is allowed to do one implicit conversion to make types match, so it uses said ctor to convert the const char * to a std::string temporary and it's smooth sailing from there since const& (const lvalue references) are allowed to bind to temporaries (and extend their lifetime).

Comments

Your Answer

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