C++ 中函数/方法/模板名称解析的偏好是什么?

发布于 2024-08-22 05:48:24 字数 933 浏览 4 评论 0原文

如果存在多种可能性,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) 来更改调用,但不能原型)。

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夜雨飘雪 2024-08-29 05:48:24

一般来说,重载解析相当复杂。

在您的情况下,这很简单:如果存在完全匹配,则不考虑函数模板。对于 free 来说是这样(标准 free 需要一个 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*)

并且 i 是返回 typeid(int).name()

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()

星軌x 2024-08-29 05:48:24

对于您关于 mallocfree 的特定问题,问题是在您对 malloc 的调用中:

void *p = malloc(10);

参数 10 被键入为 int,而运行时的 malloc() 签名则调用 unsigned 参数。由于不存在精确匹配,因此编译器更喜欢使用模板化的 malloc 来创建精确匹配。

当您调用时:

free(p);

p 的类型是 void*,它与 free() 的运行时签名完全匹配,因此编译器不会打扰使用模板化的免费

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.

倾其所爱 2024-08-29 05:48:24

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

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

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

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

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)

反话 2024-08-29 05:48:24

没有回答您提出的问题,而是您想要做什么:

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文