11

同僚のコードをレビューしていて、グローバル スコープで次のようにいくつかの定数が定義されていることがわかりました。

const string& SomeConstant = "This is some constant text";

個人的には、参照が、指定された char 配列から構築された「匿名」オブジェクトであると想定しているものを参照しているため、これは私には悪臭を放ちます。

構文的には合法であり (少なくとも VC++ 7 では)、動作しているように見えますが、実際には & を削除してもらいたいので、何をしているのか曖昧ではありません。

それで、これは本当に安全で合法ですか?構築されている一時オブジェクトの有効期間は保証されていますか? この方法で使用される匿名オブジェクトは、使用後に破棄されると常に想定していました...


したがって、私の質問は、匿名オブジェクトの有効期間にも一般化できます。標準は匿名オブジェクトの存続期間を規定していますか? 同じスコープ内の他のオブジェクトと同じ寿命を持つでしょうか? それとも、式の寿命だけが与えられていますか?


また、ローカルとして実行する場合、明らかにスコープが異なります。

class A
{
    string _str;

public:
    A(const string& str) :
        _str(str)
    {
        cout << "Constructing A(" << _str << ")" << endl;
    }

    ~A()
    {
        cout << "Destructing A(" << _str << ")" << endl;
    }
};

void TestFun()
{
    A("Outer");
    cout << "Hi" << endl;
}

ショー:

A(外側)を構築しています。A(外側)を破壊する; やあ

4

7 に答える 7

14

それは完全に合法です。プログラムが終了するまで破棄されません。

編集:はい、保証されています:

「動的ストレージ期間を持たず、スレッドストレージ期間を持たず、ローカルではないすべてのオブジェクトには、静的ストレージ期間があります。これらのオブジェクトのストレージは、プログラムの期間中持続するものとします (3.6.2、3.6.3)。 "

-- 2008 ワーキング ドラフト、プログラミング言語 C++ の標準、§ 3.7.1 p. 63

マーティンが指摘したように、これがすべての答えではありません。標準草案はさらに次のように述べています (§ 12.2, p. 250-1):

「クラス型のテンポラリはさまざまなコンテキストで作成されます: 右辺値を参照にバインドします (8.5.3) [...] 一時オブジェクトの作成が回避された場合でも (12.8)、すべてのセマンティック制限はあたかも尊重されます。 [...] 一時オブジェクトは、それらが作成されたポイントを (字句的に) 含む完全式 (1.9) を評価する最後のステップとして破棄されます [...] 2 つのコンテキストがあります[...] 2 番目のコンテキストは、参照が一時オブジェクトにバインドされている場合です。参照がバインドされている一時オブジェクト、または参照がバインドされているサブオブジェクトの完全なオブジェクトである一時オブジェクトは、以下に指定されている場合を除き、参照の存続期間中存続します。」

気分が良くなるかどうかを g++ でテストしました。;)

于 2009-06-22T17:37:43.773 に答える
11

はい、有効で合法です。

const string& SomeConstant = "This is some constant text";

// Is equivalent too:

const string& SomeConstant = std::string("This is some constant text");

したがって、一時オブジェクトを作成しています。
この一時オブジェクトは const& にバインドされているため、その有効期間は、バインドされている変数の有効期間まで延長されます (つまり、オブジェクトが作成された式よりも長くなります)。

これは規格によって保証されています。

ノート:

合法なのに。私はそれを使用しません。最も簡単な解決策は、それを const std::string に変換することです。

使用法:

この状況では、変数はグローバル スコープ内にあるため、プログラム全体で有効です。そのため、実行が main() に入るとすぐに使用でき、実行が main() を終了した後はアクセスしないでください。

技術的にはこれより前に利用できる可能性がありますが、グローバルオブジェクトのコンストラクター/デストラクターでの使用は、グローバル変数の初期化順序の既知の問題で緩和する必要があります。

余分な考え:

一方、これは問題に悩まされることはありません:

char const* SomeConstant = "This is some constant text";

そして、いつでも使用できます。ちょっとした考え。

于 2009-06-22T18:38:33.163 に答える
6

それは合法かもしれませんが、それでも醜いです。参照を省略してください!

const string SomeConstant = "This is some constant text";
于 2009-06-22T17:52:32.787 に答える
4

それは醜いのと同じくらい合法です。

于 2009-06-22T18:36:23.010 に答える
2

参照を使用して一時変数を拡張することは合法ですconst。これは Alexandrescu のScopeGaurdで使用されます。「最も重要な候補constと呼ばれる Herb Sutter によるこの優れた説明を参照してください。

つまり、この特定のケースは C++ のこの機能の悪用であり、プレーンな を残して参照を削除する必要がありますconst string

于 2009-06-22T18:35:18.410 に答える
0

さて、私が深遠な場合、人々は私を訂正します、しかしここにあなたの素晴らしい反応のすべてを聞いている私の結論があります:

A)構文的および論理的に合法であり、&は一時/匿名の存続期間を表現レベルを超えて参照の存続期間まで延長します。これをVC++7で次のように確認しました。

class A { 
    public: A() { cout << "constructing A" << endl; }
    public: ~A() { cout << "destructing A" << endl; }
};

void Foo()
{
    A();
    cout << "Foo" << endl;
}

void Bar()
{
    const A& someA = A();
    cout << "Bar" << endl;
}

int main()
{
    Foo();    // outputs constructing A, destructing A, Foo
    Bar();    // outputs constructing A, Bar, destructing A
    return 0;
}

B)それは合法ですが、実際の存続期間に関して混乱を招く可能性があり、これらの場合の参照は非参照として宣言する利点がないため、参照はおそらく避ける必要があり、余分なスペースになる可能性があります。メリットがないので、不必要な難読化です。

すべての回答をありがとう、それは非常に興味深い議論でした。つまり、長短:はい、構文的には合法です。いいえ、寿命が延びるので技術的に危険ではありませんが、何も追加されず、コストと混乱が増える可能性があります。

聞こえますか?

于 2009-06-23T15:15:45.450 に答える
0

それを const として宣言し (つまり、変更できないことを意味します)、それを参照にすることで、誰かが変更する可能性があることを意味します。これは、少なくとも悪い形式のように思えます。さらに、あなたが理解していると確信しているように、グローバル変数は悪いものであり、めったに必要ありません。

于 2009-06-22T19:06:47.767 に答える