我正在检测一些代码,并注意到使用C ++ 14功能时,有两个新的delete
运算符(来自http://en.cppreference.com/w/cpp/memory/new/operator_delete):
这些是5-6)如果是用户定义的替换,则调用而不是(1-2) 提供除了它的实现 - 定义是否(1-2)或 删除不完整类型和数组的对象时调用(5-6) 非类和易破坏的类类型(自C ++ 17以来)。该 标准库实现与(1-2)相同。
我已经超载了这些并且想要专门调用这两个。当我用gcc重载这两个时,我没有问题。使用clang ++,我得到一个未定义的operator delete(void*)
这是代码
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编译:{{1}}没有问题,运行正常。
是否可以使用llvm / clang执行此操作?
答案 0 :(得分:2)
您可以像这样显式调用大小已删除的操作符:
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
举一个完整的例子:
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) : );
}
编译并查看生成的代码后,很明显在以下情况下会调用哪些运算符:
$ 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 sized deallocation。
如果使用以下命令,您的示例编译不会出错:
clang++ -ggdb -std=c++14 -nostdlib -fno-builtin -fno-exceptions -fsized-deallocation 1.cc
由于默认情况下,禁用Clang 3.7 C ++ 14大小的释放:
C++ Support in Clang > C++14 implementation status > C++ Sized Deallocation N3778
(7):在Clang 3.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: Disable sized deallocation by default due to ABI breakage
没有广泛部署的标准库提供 释放功能,因此我们必须平移并询问用户是否要 我们使用大小分配。将来,当此类库 部署后,我们可以教驾驶员检测它们并启用它 功能。
此选项的手动输入可在此处找到:
Clang command line argument reference > Compilation flags > Target-independent compilation options
-fsized-deallocation
,-fno-sized-deallocation
启用C ++ 14大小的全局释放函数