2

複数の可能性がある場合、C ++コンパイラはどの関数/メソッドを呼び出すかをどのように決定しますか?私の特定のケースでは、C ++ランタイムの標準の無料機能があり、次のようなテンプレート化された無料のバリアントもあります。

// The definitions of the C++ Run Time Library (from memory.h)
extern malloc(size_t s);
extern void free(void *p);

// Our own memory management functions
extern void *OurMalloc(size_t s);
extern void OurFree(void *p);

// Own variants to overrule malloc and free (instead of using #define)
template<typename T>
void *malloc(T t)
{
return OurMalloc(t);
}

template<typename T>
void free(T *t)
{
OurFree(t);
}

次のコードを使用してこれをテストしました。

void main(void)
{
void *p = malloc(10);
free(p);
}

これをコンパイルして実行すると、mallocの呼び出しがテンプレート化されたバリアントに正しく置き換えられているようです。ここまでは順調ですね。

ただし、freeの呼び出しはテンプレート化されたバリアントに置き換えられず、標準のC++関数が引き続き呼び出されます。

C ++コンパイラは、優先するバリアントを決定するためにどのようなルールを使用しますか?これはケーニッヒルックアップルールに関連していますか?

注:#defineを使用しても問題が解決しないため、この代替方法を試しました(Cマクロ(#define)を使用して呼び出しを変更する方法を参照してください。プロトタイプは変更しないでください)。

4

4 に答える 4

8

オーバーロードの解決は、一般的に非常に複雑です。

あなたの場合、それは非常に簡単です。完全に一致する場合、関数テンプレートは考慮されません。無料の場合はそうです (標準の free は void* を取ります)、malloc の場合はそうではありません (標準の malloc は size_t を取ります。int を渡し、size_t を int の typedef にすることはできません -- size_t は符号なしです)。 )。void* 以外の型で free を呼び出すと、テンプレートがインスタンス化されます。

ランニング:

#include <iostream>

void* ml(size_t s)
{
    std::cout << "ml(size_t)\n";
}

void fr(void *p)
{
    std::cout << "fr(void*)\n";
}

template<typename T>
void* ml(T t)
{
    std::cout << "ml<" << typeid(T).name() << ">(T)\n";
}

template<typename T>
void fr(T *t)
{
    std::cout << "fr<" << typeid(T).name() << ">(T*)\n";
}

int main()
{
    void* p1 = ml((size_t)10);
    fr(p1);
    int* p2 = (int*)ml(10);
    fr(p2);
    return 0;
}

私は得る

ml(size_t)
fr(void*)
ml<i>(T)
fr<i>(T*)

そして私は何を返しますtypeid(int).name()

于 2010-02-23T16:27:08.837 に答える
3

とに関する特定の問題についてmallocfree問題は への呼び出しにありますmalloc:

void *p = malloc(10);

パラメータ 10 は として型指定されますintが、ランタイムの引数のmalloc()呼び出しのシグネチャです。完全一致がないため、コンパイラは完全一致を作成できるunsignedテンプレート化を優先します。malloc

電話すると:

free(p);

pisの型はvoid*ランタイムの署名と正確に一致するfree()ため、コンパイラはテンプレート化された をわざわざ使用しませんfree

于 2010-02-23T16:29:52.870 に答える
2

mallocこの手法を使用して標準を「置き換える」ことはできません。他の回答では、呼び出しの引数として符号付きmallocの値を使用しているため、標準のバージョンでは符号なしの引数が必要であるため、テンプレート化されたバージョンが標準のバージョンよりも「優先」されることはすでに説明されています。

これをよりよく説明するために、呼び出しで引数unsigned intまたはunsigned long引数を指定した場合に追加したかっただけですmalloc

void *p1 = malloc(10u);
void *p2 = malloc(10ul);

これらの呼び出しの1つでは、テンプレートバージョンmallocも「機能」しなくなり、代わりに標準バージョンが呼び出されます。これは、引数との一致が優れているためです(プラットフォームsize_tで次のいずれかとして定義されている場合) 。unsigned intまたはunsigned long

于 2010-02-23T16:35:33.270 に答える
0

あなたが尋ねた質問には答えていませんが、あなたがやろうとしているように見えること:

システムで利用できる場合は、LD_PRELOAD を使用して、自分のバージョンの malloc と free を含むビルドした .so ライブラリをプリロードできます。その後、それらは標準バージョンの代わりに確実に呼び出されます。

于 2010-02-23T16:51:18.967 に答える