1

サードパーティ ライブラリ (QtPropertyBrowser for Qt 5.0) の新しいバージョンにアップグレードしました。アップグレードにより、アプリケーションに新しいバグが発生し、ライブラリ内の静的関数を追跡することができました。関数には、関数が最初に呼び出されたときに初期化される静的変数が含まれています。初期化後にその変数のメモリ位置をコピーしたところ、予想どおり、その後の複数の呼び出しで変数が同じメモリ位置に残っていることがわかりました。次に、後続の関数呼び出しで、静的変数のメモリ位置とデータが変更されたことに気付きました (プログラムにバグが発生しました)。

コードは次のようになります。

class ClassA
{
    //.... 
};

class ClassB
{
public:
    ClassA* ptrMember;
};

static ClassA *theFunction()
{
    static ClassB statVar = {0};
    if(!statVar.ptrMember)
        statVar.ptrMember = new ClassA();
    return statVar.ptrMember;
}

theFunction()に保存されているアドレスへの複数の呼び出し中は&statVar常に同じままでしたが、その後の呼び出しではアドレス&statVarが異なり、statVar.ptrMember空であることがわかりました。

私はこれが可能だとは思わなかった!何か案は?

4

1 に答える 1

5

ヘッダー ファイルで関数を定義し、多くの.cppファイルにインクルードしたようです (各.cppファイルは 1 つの翻訳単位を定義します) 。

関数が宣言されているためstatic、各翻訳単位は変数とともに独自のバージョンを取得しstaticます。そのため、異なる翻訳単位から関数を呼び出すと、静的変数のアドレスが異なります。同じ翻訳単位から呼び出す限り、同じアドレスが表示されます。

特定の翻訳単位のアドレスは同じままであることに注意してください。各翻訳単位には独自のバージョンの静的変数があるため、アドレスが異なるだけです。もう同じ変数にアクセスしていません。それらは同じ識別子を持つ異なる変数です


問題は、これがすべてサードパーティのライブラリで定義されており、静的変数を再初期化せずに dll と exe の両方から呼び出す必要があることです。ライブラリのコードを変更せずに問題を解決する方法はありますか? 現在、ライブラリを .lib として使用しています。代わりに .dll としてコンパイルした場合、問題は解決しますか?

静的関数 (したがって静的変数) の複数のバージョンを回避するには、同じ翻訳単位から呼び出す必要があります。これを行うには、プロキシを使用して関数を呼び出すことができます。つまり、関数を直接呼び出す代わりに、プロキシを呼び出します (これは単一の翻訳単位で定義され、これ以上のバージョンはありません)。

  • ヘッダーでプロキシを宣言します。

    //proxy.h
    ClassA *proxy_of_theFunction();
    
  • 実装ファイルでプロキシを定義します。

    //proxy.cpp
    ClassA* proxy_of_theFunction()
    {
        return theFunction(); //call the actual function
    }
    

コールしproxy_of_theFunctionます。それはあなたの問題を解決するはずです。

proxy_of_theFunctionではない static(そして で定義されている)ためproxy.cpp、バージョンは 1 つしかありません。他のバージョンはありません。を呼び出すプロキシは 1 つしかないため、毎回同じtheFunction()バージョンの変数を呼び出しているため、呼び出しごとに同じバージョンの変数が表示されます。:-)theFunctionstatic

于 2013-01-22T17:38:13.097 に答える