2

Today I see this piece of code and I'm wondering to know what it is exactly doing this const reference in an assignment where a new object is created. (I don't know how to name this kind of assignments.)

std::string const& p = s.c_str(); // s is a std::string

I understand that something like std::string const& p = s; will create a reference p to s, but in the line shown we are creating a new object (using the raw pointer from std::string::c_str).

I've made a MCVE in Coliru with this:

#include <iostream>
#include <string>

void foo(std::string const& s)
{
    std::string const& p = s.c_str(); // << here
    
    std::cout << s << " " << p << " " << &s << " " << &p << std::endl;
}

int main()
{
    foo("hello");
}

And, as expected the output is showing that a new object was created:

hello hello 0x7ffdd54ef9a0 0x7ffdd54ef950

So, my question is: Is this actually doing something I'm not able to see? Does it have any problem (like a dangling reference) in the code?

2

2 Answers 2

4

From std::string::c_str's documentation, it returns:

a pointer to an array that contains a null-terminated sequence of characters (i.e., a C-string) representing the current value of the string object. That is, a const char*.

So when you wrote:

std::string const& p = s.c_str();

In the above statement, the const char* that was returned on the right hand side is used to create a temporary object of type std::string using a converting constructor that takes const char* as argument.

Next, the lvalue reference p on the left hand side is bound to that temporary obect. And in doing so, the lifetime of the temporary is extended.

To answer your last question, there is no dangling reference in your program.

Sign up to request clarification or add additional context in comments.

5 Comments

Yes, this is what I understood too, but have no idea what happened with the reference to the temporary object, if it produced a memory leak, or so.
@cbuchart There is no memory leak. The lifetime of the temporary is extended as mentioned at the end of my answer.
Without life-time extension, the problem would be dangling reference, but still no memory leaks.
@Jarod42 Correct.
You're right, I've updated the question with this lapse
3

In fact this construction

std::string const& p = s.c_str();

does not differ essentially from

std::string const p( s.c_str() );

but is more confusing.

As for the output of this statement

std::cout << s << " " << p << " " << &s << " " << &p << std::endl;

then there are outputted two different addresses. The first one is the address of the parameter s and the second one is the address of the temporary object of the type std::string created in this declaration

std::string const& p = s.c_str();

by means of the conversion constructor

basic_string(const charT* s, const Allocator& a = Allocator());

2 Comments

"more confusing" is opinion biased ;-) On the other side, it has the advantage to be sure that no extra copies happens (for example, in case the method returns already a const reference, instead of a temporary, especially when used with auto).
Or better std::string const&& ptemp( s.c_str() ); std::string const& p = ptemp;?

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.