首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++中,可以指定使用哪个delete操作符吗?

在C++中,可以指定使用哪个delete操作符吗?
EN

Stack Overflow用户
提问于 2016-01-29 05:52:30
回答 1查看 1.1K关注 0票数 6

我正在测试一些代码,并注意到使用C++14特性有两个新的delete运算符(来自删除):

如果提供了用户定义的替换,则调用5-6,而不是(1-2),除非在删除不完全类型的对象以及非类和可销毁类类型的数组(自C++17以来)时,它的实现定义是否调用(1-2)或(5-6)。标准库实现与(1-2)相同。

我已经超载了,我只想给这两个打电话。当我和gcc过载这两个人时,我没有问题。使用clang++,我得到了对operator delete(void*)的未定义引用

这是代码

代码语言:javascript
复制
void* operator new(long unsigned int howMuch) {
    return reinterpret_cast<void*>(0xdeadbeef);
}

void* operator new[](long unsigned int howMuch) {
    return reinterpret_cast<void*>(0xdeadbeef);
}

void operator delete(void* what, long unsigned int howmuch) {
        if(what != reinterpret_cast<void*>(0xdeadbeef)) __builtin_trap();
        if(howmuch != 1) __builtin_trap();
}

extern "C"
void _start() {
    delete new char;
    asm("syscall" : : "a"(60) : ); 
}

用gcc编译:g++ -ggdb -std=c++14 -nostdlib -fno-builtin -fno-exceptions 1.cc没有问题,运行良好。

用llvm/clang可以做到这一点吗?

EN

回答 1

Stack Overflow用户

发布于 2019-01-11 14:32:47

您可以显式调用大小或非大小的删除操作符,如下所示:

代码语言:javascript
复制
char* ptr = new char;
delete ptr; // compiler selects which to call
operator delete(ptr); // explicitly call the non-sized delete 
operator delete(ptr, 1); // explicitly call sized delete

举一个完整的例子:

代码语言:javascript
复制
void* operator new(long unsigned int howMuch) {                                                                                                                                               
    return reinterpret_cast<void*>(0xdeadbeef);
}

void* operator new[](long unsigned int howMuch) {
    return reinterpret_cast<void*>(0xdeadbeef);
}

void operator delete(void* what) {
    if(what != reinterpret_cast<void*>(0xdeadbeef)) __builtin_trap();
}

void operator delete(void* what, long unsigned int howmuch) {
    if(what != reinterpret_cast<void*>(0xdeadbeef)) __builtin_trap();
    if(howmuch != 1) __builtin_trap();
}

extern "C"
void _start() {
    char* ptr = new char;
    delete ptr;
    operator delete(ptr);
    operator delete(ptr, 1);
    asm("syscall" : : "a"(60) : ); 
}

编译并查看生成的代码时,可以清楚地看到在以下情况下调用了哪些操作符:

代码语言:javascript
复制
$ clang++ -std=c++14 -nostdlib  -fno-builtin  -fno-exceptions -fsized-deallocation sized-deallocation.cpp -o sized-deallocation.bin && gdb -batch -ex 'file sized-deallocation.bin' -ex 'disassemble _start' | c++filt
Dump of assembler code for function _start:
   0x0000000000401070 <+0>: push   %rbp
   0x0000000000401071 <+1>: mov    %rsp,%rbp
   0x0000000000401074 <+4>: sub    $0x10,%rsp
   0x0000000000401078 <+8>: mov    $0x1,%eax
   0x000000000040107d <+13>:    mov    %eax,%edi
   0x000000000040107f <+15>:    callq  0x401000 <operator new(unsigned long)>
   0x0000000000401084 <+20>:    mov    %rax,-0x8(%rbp)
   0x0000000000401088 <+24>:    mov    -0x8(%rbp),%rax
   0x000000000040108c <+28>:    cmp    $0x0,%rax
   0x0000000000401090 <+32>:    mov    %rax,-0x10(%rbp)
   0x0000000000401094 <+36>:    je     0x4010aa <_start+58>
   0x000000000040109a <+42>:    mov    $0x1,%eax
   0x000000000040109f <+47>:    mov    %eax,%esi
   0x00000000004010a1 <+49>:    mov    -0x10(%rbp),%rdi
   0x00000000004010a5 <+53>:    callq  0x401040 <operator delete(void*, unsigned long)>
   0x00000000004010aa <+58>:    mov    -0x8(%rbp),%rdi
   0x00000000004010ae <+62>:    callq  0x401020 <operator delete(void*)>
   0x00000000004010b3 <+67>:    mov    $0x1,%eax
   0x00000000004010b8 <+72>:    mov    %eax,%esi
   0x00000000004010ba <+74>:    mov    -0x8(%rbp),%rdi
   0x00000000004010be <+78>:    callq  0x401040 <operator delete(void*, unsigned long)>
   0x00000000004010c3 <+83>:    mov    $0x3c,%eax
   0x00000000004010c8 <+88>:    syscall 
   0x00000000004010ca <+90>:    add    $0x10,%rsp
   0x00000000004010ce <+94>:    pop    %rbp
   0x00000000004010cf <+95>:    retq   
End of assembler dump.

但是,使用Clang获取undefined reference to `operator delete(void*)'的实际原因是(正如@T.C.所说) Clang需要-fsized-deallocation标志来启用C++14大小的去分配

如果使用以下命令,则示例编译不出错:

代码语言:javascript
复制
clang++ -ggdb -std=c++14 -nostdlib  -fno-builtin  -fno-exceptions -fsized-deallocation 1.cc

由于默认情况下禁用了Clang3.7 C++14大小的取消分配:

C++ Support in Clang > C++14 implementation status > C++ Sized Deallocation N3778

(7):在Clang3.7及更高版本中,只有当用户传递-fsized-deallocation标志时才启用大小取消分配。用户必须通过显式提供或使用C++标准库来提供相应的解分配函数的定义。libstdc++在5.0版中添加了这些函数,libc++在3.7版中添加了这些函数。

Clang 3.7 Release Notes > What’s New in Clang 3.7? > New Compiler Flags

C++14的大小取消功能现在由-fsized-deallocation标志控制。此特性依赖于尚未广泛部署的库支持,因此用户必须提供额外的标志才能获得额外的功能。

这一变化的原因是,当时广泛部署的标准库(2015-03-19)中缺少这些功能:

C++14:由于ABI损坏,默认情况下禁用大小取消分配

目前还没有广泛部署的标准库提供大规模的去分配功能,因此我们不得不对用户进行分析,并询问用户是否希望我们使用“大小去分配”。将来,当这些库被部署时,我们可以教驱动程序检测它们并启用这个特性。

此选项的手动条目可在以下位置找到:

Clang command line argument reference > Compilation flags > Target-independent compilation options

-fsized-deallocation-fno-sized-deallocation 启用C++14大小的全局解分配函数

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35077781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档