1

以下の C++ コードは、Visual Studio 2008 で次の警告を生成します。

1>c:...\sample.cpp(6): 警告 C4717: 'operator<': すべての制御パスで再帰的、関数は > ランタイム スタック オーバーフローを引き起こす

operator< が必要な状況で Sample クラスを使用すると、実際にはスタック オーバーフロー エラーでクラッシュします (たとえば、マルチセットに 2 番目の Sample オブジェクトを挿入した後)。コンストラクターは、スタック領域がなくなるまで呼び出され続けます。

以下のコードは、単独で警告を生成するために必要なすべてのコードです (Sample クラスを参照するコード内には何もありません)。

// Sample.hpp
#include <iostream>

class __declspec(dllexport) Sample
{
  std::string ID;
public:
  Sample (std::string id):ID(id) {};
  friend bool __declspec(dllexport) operator<(const Sample& s1, const Sample& s2);
};


// Sample.cpp
#include "Sample.hpp"

bool operator<(const Sample& s1, const Sample& s2)
{
  return s1.ID<s2.ID;
}

この警告は、Win7 上の VC++ および VS2008 (Win32、/W3) で表示されます。同じプラットフォームとまったく同じコードの場合、Eclipse で MinGW GCC 4.7.3 を使用すると、警告は表示されません。

< string > ヘッダーを追加すると、VS2008 で警告が消え、Sample クラスを使用しても問題なく動作します。

また、Sample コンストラクターを明示的に宣言すると、VS2008 は次のコンパイル エラーをスローします。

1>.\Sample.cpp(5) : エラー C2678: バイナリ '<' : 型 'const std::string' の左側のオペランドを取る演算子が見つかりません (または、受け入れ可能な変換がありません) 1> c :...\Sample.hpp(13): 引数リスト '(const std::string, const std::string )'

ただし、GCC でコンストラクターを明示的に設定しても、警告もエラーも生成されません (Eclipse で警告をできる限り包括的なレベルに設定しました)。

VS2008 がこのスタック オーバーフロー警告をいつ生成するかを決定する方法を誰かが大まかに説明できるかどうか知りたいです。この場合、それは正しいことが判明したので、それがどのように行われるかを知りたいです. また、可能であれば、ここで GCC の動作が異なる理由を教えてください。うまくいけば、これは理にかなっています。

4

1 に答える 1

3

これは、比較の時点でstd::stringが不完全な型であり、変換コンストラクターSample (std::string id)暗黙的に呼び出されているために発生しています。式s1.ID<s2.IDでは、LHS と RHS の両方が暗黙的に一時に変換されSample、変換演算子が再度 (そして何度も) 呼び出されます。

<string>の完全な定義std::stringが表示れるように含める必要があり、 sample のコンストラクターを宣言することを強くお勧めしますexplicit

于 2013-08-04T00:28:22.253 に答える