web-dev-qa-db-ja.com

static const std :: stringを作成すると例外が発生するのはなぜですか?

アプリの複数の場所で使用する文字列用の文字列定数があります。

namespace Common{
    static const std::string mystring = "IamAwesum";
}

他の何かについて質問を投稿するとき( コンパイル中にターゲットに含まれていない.hファイルはどうなりますか? )、別のユーザーが次のコメントをしました:

この場合、静的文字列はグローバルであることに注意してください。したがって、それらはいつでも例外を作成する可能性があり、キャッチすることはできません。文字列の参照を返す関数を使用することをお勧めします。 std :: string const&mystring {static std :: string const mystring = "IamAwesum";この方法でmystringを返す}オブジェクトは必要な場合にのみ構築されます

上記の方法で静的const文字列を使用すると、例外がスローされるリスクがある理由を誰かが説明できますか?

25
Kaizer Sozay

N4140§3.6.2[basic.start.init]/4

静的ストレージ期間を持つ非ローカル変数の動的初期化がmainの最初のステートメントの前に行われるかどうかは実装によって定義されます。

N4140§N414015.3[.handleを除く]/13

静的ストレージ期間を持つオブジェクトのデストラクタまたは静的ストレージ期間を持つ名前空間スコープオブジェクトのコンストラクタでスローされる例外は、main()の-​​function-try-blockによってキャッチされません。

文字列のコンストラクタによって生成された例外をキャッチすることはできません-たとえば、std::bad_alloc

(意見)そうは言っても、そのような小さな弦については、この種の配慮は妄想的だと思います。

31
krzaq

唯一の「問題」-あなたがそれをそれと呼ぶことができるなら-私があなたのコードで見るのは、動的に割り当てられたバッファ(つまり正式に =一定ですが、実際にはそうではありません)。これは、必要な2倍の物理メモリを使用し、不要なコピーを実行します。

それは重要ですか?ほぼ間違いなく、違います。 「かなり制限されたメモリ」システムであっても、実行時間の観点からも、メモリ消費量の観点からも、これは今日ではほとんど目立たないでしょう。

例外については、もちろん技術的にstd::stringが行わなければならない割り当てはcould失敗するため、コンストラクターcould =投げると、捕まえられなくなります。しかし、現実的にしてください。
これが起こらないことはほぼ保証されていますが、起こったとしても...プログラムの起動中にいくつかの文字列にメモリを割り当てるなどの些細なことが失敗した場合、本当に深刻な問題が発生します。全く違うスケール!
さらに、上記の別の回答へのコメントで指摘されているように、これが起こったと仮定して、あなたはそれについて何をするつもりですか?プログラムは完全に実行できないので、おそらく実行できるプログラムを強制終了することはほとんどありません。

さて、C++ 17はそれほど遠くなく、string_viewはすでにいくつかの主流コンパイラのstd::experimentalで利用可能であるため、試すことができる別のことがあります:正しいものを使用してください

string_viewは、stringとは異なり、非定数メモリを割り当てず、定数データをそのメモリにコピーしてから、ふり定数です。代わりに、定数データへのポインターを直接管理し、それだけです。
そうすれば、定数は本当に(正式にだけでなく)定数であり、割り当て、例外の可能性、および二重メモリ使用量はありません。そして、ほとんどの場合、それはまだstringのように見え、匂いがします。唯一の注目すべき違いは、string_viewがヌル終了を保証しないこと(ただし、それが指す文字定数はそうするので、これは無関係です)と、それが本当に定数であるという事実です。変更できません...まさにあなたが望むものです。

4
Damon

Pdfドキュメントは主に、静的または動的にリンクされたライブラリを使用したオブジェクトctorおよび初期化順序の大失敗からの例外に言及しています。

例外についてコードに見られる唯一の危険は、std :: stringのctorが呼び出されたときにスローされる場合です。

本当に安全を確保したい場合は、代わりにstatic const char * mystringを使用できます。これはC++ ctorを呼び出しません。

コードが共有ライブラリにあり、プロセスのアドレス空間に配置する必要があるという問題もあります。複雑なctor(投げることができるctor)を使わなければ、それは大きな問題ではないと思います。

4
Jonathan