2010-12-06 6 views
5

Ich habe den folgenden Code, der ohne Warnungen kompiliert (-Wall -pedantic) mit g ++C++ Übergabe eines String-Literals anstelle einer const std :: string &?

#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; 
} 

Aber wenn ich es laufen, wird nur das Newline ausgedruckt. Was ist los?

Wenn ich diese innerhalb Sachen tun war:

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

dann funktioniert es gut!

Antwort

18

Der Grund, warum dies versagt, ist, weil es im Wesentlichen unter der Haube zu den folgenden kompiliert.

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

In diesem Fall wird der Wert Foo eine Referenz auf ein temporäres Objekt nimmt die nach der Konstruktor gelöscht wird vervollständigt. Daher wird ein totaler Wert beibehalten. Die zweite Version funktioniert, weil sie einen Verweis auf eine lokale enthält, die eine längere Lebensdauer hat als die Foo-Instanz.

Um dies zu beheben, ändern Sie das Memebr von einem const std::string& zu einem const std::string.

+0

Prost, weiß nicht, warum mein Gehirn das nicht bekam: s –

+0

Es hat keinen Sinn, einen konstanten Wert als Parameter zu nehmen. Verwenden Sie einfach 'std :: string'. –

+1

@MilesRout Das stimmt nicht ganz. Möglicherweise wissen Sie, dass Sie die Zeichenfolge nicht ändern möchten, und indem Sie sie als const deklarieren, können Sie dem Compiler bestätigen, dass Sie dies nicht tun. – Erik

2

Was passiert ist, dass die Referenz 'str' initialisiert wird, so dass es auf die temporäre arg, 's' zeigt. Es ist ziemlich genau so wie mit einem Zeiger - Sie zählen auf die fortdauernde Existenz Ihres Konstruktors arg, 's'. Wenn das Temporäre gelöscht wird (nachdem der Konstruktor ftn zurückgegeben wurde), zeigt Ihre Referenz jetzt auf den Wert "Müll".

Um zu beheben, ändern Sie str, so dass es ein tatsächliches String-Objekt und keine Referenz ist.

const std :: string str;

Auf diese Weise wird eine Kopie Ihrer Arg-Zeichenfolge erstellt, und diese Kopie wird die gleiche Lebensdauer wie Ihr Foo-Objekt haben.

Verwandte Themen