Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my string reference member variable set to an empty string in C++?

Consider the following code:

class Foo
{
private:
    const string& _bar;

public:
    Foo(const string& bar)
        : _bar(bar) { }

    const string& GetBar() { return _bar; }
};

int main()
{
    Foo foo1("Hey");
    cout << foo1.GetBar() << endl;

    string barString = "You";
    Foo foo2(barString);
    cout << foo2.GetBar() << endl;
}

When I execute this code (in VS 2013), the foo1 instance has an empty string in its _bar member variable while foo2's corresponding member variable holds the reference to value "You". Why is that?

Update: I'm of course using the std::string class in this example.

like image 214
feO2x Avatar asked Jan 13 '15 16:01

feO2x


People also ask

Is std :: string empty?

std::string::emptyReturns whether the string is empty (i.e. whether its length is 0). This function does not modify the value of the string in any way.

What is empty string CPP?

It returns whether the string is empty (i.e. whether its length is 0).

How do you pass an empty string in C++?

std::string::clear in C++ The string content is set to an empty string, erasing any previous content and thus leaving its size at 0 characters.


2 Answers

For Foo foo1("Hey") the compiler has to perform a conversion from const char[4] to std::string. It creates a prvalue of type std::string. This line is equivalent to:

Foo foo1(std::string("Hey"));

A reference bind occurs from the prvalue to bar, and then another reference bind occurs from bar to Foo::_bar. The problem here is that std::string("Hey") is a temporary that is destroyed when the full expression in which it appears ends. That is, after the semicolon, std::string("Hey") will not exist.

This causes a dangling reference because you now have Foo::_bar referring to an instance that has already been destroyed. When you print the string you then incur undefined behavior for using a dangling reference.

The line Foo foo2(barString) is fine because barString exists after the initialization of foo2, so Foo::_bar still refers to a valid instance of std::string. A temporary is not created because the type of the initializer matches the type of the reference.

like image 192
template boy Avatar answered Sep 30 '22 12:09

template boy


You are taking a reference to an object that is getting destroyed at the end of the line with foo1. In foo2 the barString object still exist so the reference remains valid.

like image 38
NathanOliver Avatar answered Sep 30 '22 14:09

NathanOliver