What is the preference of function/method/template name resolving in C++?

隐身守侯 提交于 2019-12-11 00:29:59

问题


How does the C++ compiler decide which function/method to call if there are multiple possibilities? In my specific case I have the standard free function of the C++ Run time and I also have a templated free variant, like this:

// 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);
}

I tested this using the following code:

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

If I compile and run this, it seems that the call to malloc is correctly replaced by the templated variant. So far, so good.

However, the call to free is not replaced by the templated variant, and the standard C++ function is still called.

What rules does the C++ compiler use to decide which variant to give priority? Is this related to the Koenig-lookup rules?

Note: I tried this alternative because using #define does not solve the problem (see question How to use C macro's (#define) to alter calls but not prototypes).


回答1:


Overload resolution is quite complicated in general.

In your case, it is quite easy: a function template is not considered if there is an exact match. For free it is the case (the standard free takes a void*), for malloc it isn't (the standard malloc takes a size_t, you are passing an int and size_t can't be a typedef for int -- size_t is unsigned). If you call free with a type other than void*, it should instantiate your template.

Running:

#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;
}

I get

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

and i is what returns typeid(int).name()




回答2:


For your particular issue about malloc and free, the problem is that in your call to malloc:

void *p = malloc(10);

the parameter 10 is typed as an int, while the signature for the runtime's malloc() calls for an unsigned argument. Since there's not an exact match, the compiler prefers the templated malloc where it can create an exact match.

When you call:

free(p);

the type of p is void* which does exactly match the runtime's signature for free() so the compiler doesn't bother using the templated free.




回答3:


It is not possible to "replace" the standard malloc using this technique. Other answers have already explained that because you are using a signed value as an argument in malloc call, your templated version happens to "win" over the standard one because the standard one expects an unsigned argument.

To better illustrate this I just wanted to add that if you supply either an unsigned int or unsigned long argument in your malloc call

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

and you'll notice that in one of these calls your templated version of malloc also doesn't "work" anymore and the standard one is called instead, since it is a better match for the argument (provided that on your platform size_t is defined as either unsigned int or unsigned long)




回答4:


Not answering the question you asked, but what it seems like you're trying to do:

If it's available on your system, you can use LD_PRELOAD to preload a .so library you build that has your versions of malloc and free. Then they will definitely be called instead of the standard versions.



来源:https://stackoverflow.com/questions/2319772/what-is-the-preference-of-function-method-template-name-resolving-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!