在优化时,海湾合作委员会为什么默认情况下使用尺寸感知的删除操作员?

发布于 2025-01-30 02:21:33 字数 872 浏览 3 评论 0 原文

如果我定义自己的 delete 运算符,如下所示:

#include <cstdio>
#include <cstdlib>
#include <new>

void* operator new (size_t count)
{
    printf("Calling custom new!\n");
    return malloc(count);
}

void operator delete(void *p) noexcept
{ printf("Called size unaware delete!\n");
  free(p);
}

int main()
{
    int *a = new int{1};
    delete a;
}

并使用 gcc 版本12.1编译,则使用 -O2 -WALL < /code>指定的选项,我得到不匹配的新删除警告。查看编译的输出,我看到编译器使用size Aware delete operator(signature void operator delete(void *p,std :: size_t sz); )而不是我定义的自定义一个(请参阅 Compiler Explorer输出有关详细信息)。

其他编译器,例如 clang 使用我定义的删除操作员,因此不会导致不匹配的操作员警告。为什么 GCC 在优化时使用大小吸引版本?

If I define my own new and delete operators as shown below:

#include <cstdio>
#include <cstdlib>
#include <new>

void* operator new (size_t count)
{
    printf("Calling custom new!\n");
    return malloc(count);
}

void operator delete(void *p) noexcept
{ printf("Called size unaware delete!\n");
  free(p);
}

int main()
{
    int *a = new int{1};
    delete a;
}

and compile using gcc version 12.1, with -O2 -Wall options specified, I get a mismatched-new-delete warning. Looking at the compiled output, I see that the compiler uses the size-aware delete operator (signature void operator delete(void *p, std::size_t sz);) instead of the custom one I defined (see compiler explorer output for details).

Other compilers such as clang use the delete operator I defined, and thus do not result in that mismatched operator warning. Why does gcc use the size-aware version when optimizing?

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

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

发布评论

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

评论(1

一人独醉 2025-02-06 02:21:33

参考文献是C ++ 20草稿(N4861)。我还假设C ++ 14或更高版本,它引入了尺寸吸引的DealLocation函数。

在您的特定示例中,需要删除表达式来调用size Aware 操作员删除,因为要破坏的类型已完成。因此,海湾合作委员会的行为正确。 /10.5 )

(请参阅 [expr.delete ] 但是,选择尺寸感知器的问题不是问题,因为全局操作员的默认行为删除(void*,size_t) Overload(如果不替换)就是要调用相应的运算符删除(void*),因此您的自定义实现最终仍将使用。 (请参阅 [new.delete.single] >)

然而, [new.delete.single ]/11 一个替换运算符delete 版本的程序,没有 size_t 参数还应用 size_t parameter替换一个程序。便条澄清说,尽管当前标准库提供了尺寸吸引版本的默认行为,无论如何都将其称为自定义的非大小意识实现,但可能会改变未来的标准修订版。

此外,允许编译器在给定的示例中同时调用运算符的调用新操作员删除以不同的方式提供存储 Main 的全身,没有其他可观察到的副作用。因此,根本没有调用运算符删除

因此,为了使未来的代码进行防止,并避免使用Linter警告为尺寸吸引的全球超负荷增加了一个替代

void operator delete(void *p, std::size_t) noexcept
{
    ::operator delete(p);
}

品到尺寸 - unaware版本,而不会影响内存分配。 (请参阅 [new.delete.single] >)


尽管自C ++ 14以来需要,但默认情况下,Clang似乎并没有启用尺寸吸引的DealLocation函数。您需要添加 -fsized-dealLocation 标志以启用它们。

默认情况下启用它的补丁的一些讨论似乎正在进行在这里


另请注意,您的操作员的实现new 被损坏了。 运算符的投掷版本不允许返回空指针。因此,您必须检查 malloc 的返回值,并扔 std :: bad_alloc (如果为null)。

References are to the post-C++20 draft (n4861). I am also assuming C++14 or later, which introduced size-aware deallocation functions.

For your particular example, the delete expression is required to call the size-aware operator delete, since the type to be destroyed is complete. So GCC is behaving correctly. (see [expr.delete]/10.5)

It is however not a problem that the size-aware one is chosen, because the default behavior of the global operator delete(void*, size_t) overload, if not replaced, is to just call the corresponding operator delete(void*), so your custom implementation will still be used in the end. (see [new.delete.single]/16)

There is however a recommendation in [new.delete.single]/11 that a program which replaces the operator delete version without size_t parameter should also replace the one with the size_t parameter. A note clarifies that although currently the standard library supplied default behavior of the size-aware versions call the custom non-size-aware implementation anyway, that may change in future standard revisions.

Also, the compiler is allowed to elide both the call to operator new and operator delete in the given example to either provide storage in a different manner or more likely to just elide the whole body of main which has no other observable side effects. So it is possible that no operator delete is called at all.

So, to future-proof the code and avoid linter warnings add a replacement for the size-aware global overload as well

void operator delete(void *p, std::size_t) noexcept
{
    ::operator delete(p);
}

Also note that the standard requires the replacement of this overload to behave in such a way that it could always be replaced by a call to the size-unaware version without affecting memory allocation. (see [new.delete.single]/15)


Although required since C++14, Clang doesn't seem to enable size-aware deallocation functions yet by default. You need to add the -fsized-deallocation flag to enable them.

Some discussion of a patch enabling it by default seems to be going on here.


Also note that your implementation of operator new is broken. The throwing version of operator new is not allowed to return a null pointer. So you must check the return value of malloc and throw std::bad_alloc if it is null.

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