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++ 编译器使用什么规则来决定优先考虑哪个变体?这与 Koenig 查找规则有关吗?

注意:我尝试了这种替代方法,因为使用 #define 不能解决问题(请参阅问题如何使用 C 宏 (#define) 来更改调用而不是原型)。

4

4 回答 4

8

重载解析通常相当复杂。

在您的情况下,这很容易:如果存在完全匹配,则不考虑函数模板。对于免费是这种情况(标准的免费需要一个 void*),对于 malloc 它不是(标准的 malloc 需要一个 size_t,您正在传递一个 int 并且 size_t 不能是 int 的 typedef - size_t 是无符号的)。如果您使用 void* 以外的类型调用 f​​ree,它应该实例化您的模板。

跑步:

#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

对于您关于mallocand的特定问题free,问题在于您致电malloc

void *p = malloc(10);

参数 10 键入为int,而运行时malloc()调用unsigned参数的签名。由于没有完全匹配,编译器更喜欢malloc可以创建完全匹配的模板。

你打电话时:

free(p);

pis的类型void*与运行时的签名完全匹配,free()因此编译器不会打扰使用 templated free

于 2010-02-23T16:29:52.870 回答
2

malloc使用这种技术不可能“替换”标准。其他答案已经解释过,因为您在调用中使用有符号值作为参数malloc,所以您的模板版本恰好“胜过”标准版本,因为标准版本需要一个无符号参数。

为了更好地说明这一点,我只想补充一点,如果您在调用中提供unsigned intorunsigned long参数malloc

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

您会注意到,在其中一个调用中,您的模板版本malloc也不再“工作”,而是调用标准版本,因为它更适合参数(前提是在您的平台size_t上定义为unsigned intunsigned long

于 2010-02-23T16:35:33.270 回答
0

没有回答您提出的问题,但您似乎正在尝试做的事情:

如果它在您的系统上可用,您可以使用 LD_PRELOAD 预加载您构建的具有您的 malloc 和免费版本的 .so 库。那么他们肯定会被调用而不是标准版本。

于 2010-02-23T16:51:18.967 回答