Visual Studio 2012 Update 3 の C++ コンパイラで、やや目立たないが恐ろしいバグを発見したと思います。gtest を使用して単体テストを書いているときに見つけました。テストでメモリ リークが発生し始め、調査した結果、問題はコンパイラのバグに縮小されたように見えました。
Microsoft に問題を提出しました: https://connect.microsoft.com/VisualStudio/feedback/details/794722/parameter-dtor-not-called-when-overloaded-operator-involved-in-return
過去に、私は認めたくないほど多くの自分自身のバグを誤って「コンパイラのバグ」と呼んでいました。そのため、誰かが自分で問題を再現しようとする場合に備えて、ここに質問を投稿すると思いました。このコードで私自身の間違いを指摘できれば、それは非常に役に立ちます! 次のプログラムで VC++ コンパイラがデストラクタの呼び出しに失敗するのは、実際にはそうではないことを願っています。
オプティマイザーが無効になっていると問題のある動作が発生するため、オプティマイザーのバグではないことに注意してください。
このコードを gcc 4.2.1 (i686-apple-darwin11) で試したところ、期待どおりに動作しました。
プロジェクト内の単一のソース ファイルのコードは次のとおりです。
#include <string>
int instance_count= 0;
class c {
public:
c( std::string s ) : m_s(s) { ++instance_count; }
c( const c& other ) : m_s(other.m_s) { ++instance_count; }
~c() {--instance_count;}
private:
std::string m_s;
};
class d {
public:
d() {}
void operator=(int) {}
};
void f( c c_ ) {
try {}
catch(...) { return d() = 5; }
}
int main( int argc, char* argv[] ) {
c instance("leak");
f(instance);
return instance_count == 1 ? 0 : -1;
}
Visual Studio 2012 Update 3 でコンパイルするには:
- [ファイル] -> [新規] -> [プロジェクト...] で、[Win32 コンソール アプリケーション] を選択し、[OK] をクリックしてから [完了] をクリックします。
- ビルド -> 構成マネージャー -> アクティブ ソリューション プラットフォーム -> 新規...、x64 を選択し、[OK] をクリックします。
- メインの .cpp ファイルの内容を上記のコードに置き換えます
- ファイルの先頭に #include "stdafx.h" を追加するか、プリコンパイラ ヘッダーをオフにします。
- プログラムを実行します。終了コードが -1 であることに注意してください。0 であると予想されます。これは、32 ビットと 64 ビットの両方のビルドで再現されるようですが、私は 64 ビットに焦点を当てていました。
- f() の try/catch ブロックをコメント アウトします。終了コードが 0 になることに注意してください。catch() ブロックが実行されていないため、この変更が終了コードに影響する理由がわかりません。