如果有多种可能性,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 ++编译器使用哪些规则来决定哪个变体优先? 这与Koenig查找规则有关吗?
注意:我尝试了这种替代方法,因为使用#define无法解决问题(请参阅问题How to use C macro's (#define) to alter calls but not prototypes)。
答案 0 :(得分:8)
一般来说,过载分辨率非常复杂。
在您的情况下,这很容易:如果存在完全匹配,则不考虑函数模板。免费是这种情况(标准free取一个void *),对于malloc它不是(标准malloc接受size_t,你传递一个int而size_t不能是int的typedef - size_t是unsigned )。如果使用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()
答案 1 :(得分:3)
对于您关于malloc
和free
的特定问题,问题在于您致电malloc
:
void *p = malloc(10);
参数10的类型为int
,而运行时malloc()
的签名则调用unsigned
参数。由于没有完全匹配,编译器更喜欢模板malloc
,它可以创建完全匹配。
致电时:
free(p);
p
的类型是void*
,它与free()
的运行时签名完全匹配,因此编译器不会使用模板free
。
答案 2 :(得分:2)
使用此技术无法“替换”标准malloc
。其他答案已经解释过,因为您在malloc
调用中使用 signed 值作为参数,所以您的模板化版本恰好“胜过”标准版本,因为标准版本需要无符号参数。
为了更好地说明这一点,我只想补充一点,如果您在unsigned int
电话中提供unsigned long
或malloc
参数
void *p1 = malloc(10u);
void *p2 = malloc(10ul);
并且您会注意到在其中一个调用中,malloc
的模板化版本也不再“工作”,而是调用标准版本,因为它更适合参数(提供您平台size_t
上的内容定义为unsigned int
或unsigned long
)
答案 3 :(得分:0)
没有回答你提出的问题,但是你似乎想要做的事情:
如果它在您的系统上可用,您可以使用LD_PRELOAD预加载您构建的具有malloc和free版本的.so库。然后肯定会调用它们而不是标准版本。