1

過去に、ソフトウェアでさまざまなメモリリークが発生しました。これらは主に、Queue-Message-Dataなどを解放する独自の「無料」メソッドの誤った使用が原因で発生したことがわかりました。

問題は、私たちの最も深いツール関数には、動的に割り当てられたメモリを解放するための2つの方法があり、次のシグネチャがあります。

void free (void *pData);
void free (void **ppData);

どちらの方法も基本的に同じことを行いますが、2番目の方法が最初にデータを逆参照する点が異なります。これら2つのうちの一方だけですべてを実行できることは知っていますが、ソフトウェアは何年も前にそのように設計されており、現在は両方を使用してコードがどこにでもあると言えます。

誰かが次のようにこれらのメソッドの呼び出しを実装すると、問題が発生します。

QueueMessage *pMsg;
pMsg = myQueue.read(...); // dynamically allocates space for the msg and fills it
// Do something
myQueue.free(&pMsg); // << WRONG!

上記のコードは、メッセージへのポインタをfree-methodに渡す必要があります。基本的には機能しますが、この場合、コンパイラはどの関数を使用するかわからないため、ポインタが指すメモリではなく、ポインタfree(void *pData)を解放しようとするメソッドを使用します。もちろん、解決策は次のいずれかで簡単です。または

myQueue.free(pMsg);

myQueue.free((void**)&pMsg);

どちらも機能します。問題と解決策について説明したので、知りたいのですが、これらのメソッドを使用するプログラマーがそれらを正しい方法で使用することを保証できる方法はありますか?VS2005のヘッダー注釈について読んだことがあります。これは非常に便利ですが、必要なことを実行していないようです。ポインターの参照が最初のメソッドに渡された場合に警告を生成する方法があれば素晴らしいので、プログラマーは少なくとも自分のコードに何か問題があるというヒントを得ることができます。

ちなみに、私はMicrosoft VS2005を使用しており、必要に応じてVS2008にアップグレードする可能性があります。これはVS2005に移行されたC++アプリケーションであるため、.NET互換です。

4

1 に答える 1

5

テンプレートを試す:

template <class T> void free (T *pData);
template <class T> void free (T **ppData);

これにより、引数の型が完全に一致するため、コンパイラは正しい実装を呼び出す必要があります。

の元のvoid-pointer実装をfreeテンプレート化されたバージョンに置き換えるか、テンプレート化されたバージョンに元のvoid-pointerバージョンを呼び出させることができます。

template <class T> void free (T *pData)
{
    free(static_cast<void *>(pData));
}

template <class T> void free (T **ppData)
{
    free(static_cast<void **>(ppData));
}

編集:では、元のバージョンでは何が起こっていたのでしょうか?

オーバーロードされた関数解決のルールはかなり複雑ですが、原則として、コンパイラーは最初に引数型の正確な計算を見つけようとします。見つからない場合は、適用できるさまざまな自動型変換があります。

これらの自動型変換の1つは、ポインターからポインターを含む任意のポインターをポインターに変換できることvoid *です。ただし、型指定されたポインターからポインター(T **)を自動的に無効なポインターからポインター()に変換できるという規則はありませんvoid **。これが、すべての通話がに行われる理由free(void *)です。

テンプレートバージョンを導入すると、これが変わります。free(T *)これで、コンパイラーは、実行するすべての呼び出し(または)に完全に一致するものを見つけることができますfree(T **)。これにより、コンパイラーは正しいバージョンを呼び出すことができます。

于 2009-09-04T09:26:27.113 に答える