在优化时,海湾合作委员会为什么默认情况下使用尺寸感知的删除操作员?
如果我定义自己的新
和 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
在优化时使用大小吸引版本?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
参考文献是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警告为尺寸吸引的全球超负荷增加了一个替代
品到尺寸 - 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 correspondingoperator 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 withoutsize_t
parameter should also replace the one with thesize_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
andoperator delete
in the given example to either provide storage in a different manner or more likely to just elide the whole body ofmain
which has no other observable side effects. So it is possible that nooperator 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
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 ofoperator new
is not allowed to return a null pointer. So you must check the return value ofmalloc
and throwstd::bad_alloc
if it is null.