2010-12-06 12 views
5

私はグラムと警告なし(-Wall -pedantic)++C++は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; 
} 

しかし、私はそれを実行したときに、唯一の改行がプリントアウトされてコンパイルし、次のコードを持っています。 何が起こっているのですか?私は、この内部のものを行うとしたら

は:

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

は、それが正常に動作します!

答えて

18

これが失敗する理由は、本質的にボンネットの下で次のようにコンパイルされるためです。

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

この場合Foo値は、コンストラクタが完了した後に削除される一時的なオブジェクトへの参照を取っています。したがって、それは死んだ価値を保持しています。 2番目のバージョンは、Fooインスタンスよりも寿命が長いローカルへの参照を保持しているため動作します。

この変更を修正するには、const std::string&からconst std::stringに変更してください。

+0

私の脳がそれを得ていない理由を知りません:s –

+0

パラメータとしてconst値をとっている点はありません。 'std :: string'を使用してください。 –

+1

@MilesRoutそれは全く真実ではありません。文字列を変更したくないことを知っているかもしれませんし、constを宣言することで、コンパイラがそうでないことを確認できるようになります。 – Erik

2

何が起きているのかは、参照 'str'が一時的な引数 's'を指すように初期化されているということです。ポインタを使うのとほとんど同じです。あなたのコンストラクタarg、sの存続を期待しています。テンポラリが削除されると(コンストラクタftnが返った後)、参照はガーベジを指すようになります。

修正するには、実際の文字列オブジェクトであり参照ではないようにstrを変更します。

const std :: string str;

このようにして、arg文字列のコピーが作成され、そのコピーのFooオブジェクトと同じ寿命が得られます。

関連する問題