Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ passing a string literal instead of a const std::string&?

I have the following code which compiles with no warnings (-Wall -pedantic) with g++

#include <iostream>
#include <string>

using namespace std;

class Foo
{
public:
    Foo(const std::string& s) : str(s)
    { }

    void print()
    {
        cout << str << endl;
    }

private:
    const std::string& str;
};


class Bar
{
public:

    void stuff()
    {
        Foo o("werd");
        o.print();
    }
};


int main(int argc, char **argv)
{
    Bar b;
    b.stuff();

    return 0;
}

But when I run it, only the newline is printed out. What is going on?

If I were to do this inside stuff:

string temp("snoop");
Foo f(temp);
f.print();

then it works fine!

like image 912
Victor Parmar Avatar asked Dec 06 '10 18:12

Victor Parmar


2 Answers

The reason why this fails is because it essentially compiles to the following under the hood.

Foo o(std::string("wurd"));

In this case the Foo value is taking a reference to a temporary object which is deleted after the constructor completes. Hence it's holding onto a dead value. The second version works because it's holding a reference to a local which has a greater lifetime than the Foo instance.

To fix this change the memebr from being a const std::string& to a const std::string.

like image 174
JaredPar Avatar answered Oct 27 '22 03:10

JaredPar


Whats happening is that the reference 'str' is being initialized so that it points to the temporary arg, 's'. Its pretty much the same as using a pointer - you're counting on the continued existence of your constructor arg, 's'. When the temporary is deleted (after the constructor ftn returns), then your reference now points at garbage.

To fix, change str so that its an actual string object and not a reference.

const std::string str;

That way a copy will be made of your arg string, and said copy will have the same lifespan as your Foo object.

like image 41
Bzzt Avatar answered Oct 27 '22 04:10

Bzzt