我想知道是否有可能delete
在编译时检测到以下注释的错误?特别是,我想了解g ++编译器。
ClassTypeA *abc_ptr = new ClassTypeA[100];
abc_ptr[10].data_ = 1;
delete abc_ptr; // error, should be delete []
std::unique_ptr<ClassTypeA[]>
,然后您不需要。
我想知道是否有可能delete
在编译时检测到以下注释的错误?特别是,我想了解g ++编译器。
ClassTypeA *abc_ptr = new ClassTypeA[100];
abc_ptr[10].data_ = 1;
delete abc_ptr; // error, should be delete []
std::unique_ptr<ClassTypeA[]>
,然后您不需要。
Answers:
通常,编译器无法检测到此类错误。示例:假设某个类的构造函数使用分配了一些数据成员new TypeName[]
,但析构函数错误地使用delete
而不是delete[]
。如果构造函数和析构函数是在单独的编译单元中定义的,则编译器如何在编译定义析构函数的文件时知道其用法与定义构造函数的单独编译文件中的用法不一致?
关于GNU编译器,事实并非如此。如上所述,在一般情况下不能这样做。编译器不必检测此类不匹配的新/删除错误,因为这是未定义的行为。UB是编译器供应商的“摆脱监狱”卡。
诸如valgrind之类的工具可以并且确实能够检测到这些新的/删除的不匹配,但是可以在运行时检测到。可能会有一个静态分析工具查看所有最终将被编译以形成可执行文件的源文件,但是我没有任何此类静态分析工具能够检测到此类错误。
您可以将适当的RAII类用于delete
。这是唯一安全的方法,该错误只是您delete
自己遇到的很多错误之一。
始终使用类来管理动态生命周期资源,类型系统将强制执行正确的资源销毁。
编辑:“如果您正在审核代码并且无法更改它,该怎么办?” 你他妈的。
这个特别的错误-是的。这种类型的错误一般:不幸的是,没有!那将涉及在不实际执行的情况下预测执行流程,而这对于任意程序都是不可能的。(这就是为什么大多数编译器甚至不尝试检测像您的示例这样的简单情况的原因。)
因此,DeadMG的答案是合适的答案:不要试图通过注意力使它正确-人类的注意力是容易犯错的。使用语言提供的方法,并让计算机注意。
ClassTypeA*
因此您可以在new和delete之间插入一行。if ( rand() % 2 == 1 ) abc_ptr = new ClassTypeA;
静态类型系统中的任何内容都不会显示是abc_ptr
指向数组还是指向动态对象,还是指向另一对象或数组的一部分。
abc_ptr
,否则它将如何释放适当的内存量?因此,运行时知道必须释放多少个对象。
您显示的琐碎情况可以在编译时检测到,因为对象的实例化和销毁在同一范围内。通常,删除与实例化不在同一范围内,甚至在同一源文件中。C ++指针的类型不携带有关它是引用其类型的单个对象还是数组的信息,更不用说分配方案了。因此,通常不可能在编译时对此进行诊断。
为什么不诊断可能的特殊情况?
在C ++中,已经存在用于处理与范围相关联的动态资源泄漏的工具,即智能指针和更高级别的数组(std::vector
)。
即使您使用正确的delete
样式,您的代码仍然不是异常安全的。如果之间的代码new[]
,并delete[]
通过动态退出终止,删除从未执行。
就运行时检测而言,该Valgrind
工具可以很好地在运行时进行检测。看:
==26781== Command: ./a.out
==26781==
==26781== Mismatched free() / delete / delete []
==26781== at 0x402ACFC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781== by 0x8048498: main (in /home/kaz/test/a.out)
==26781== Address 0x4324028 is 0 bytes inside a block of size 80 alloc'd
==26781== at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781== by 0x8048488: main (in /home/kaz/test/a.out)
当然,Valgrind并不能在所有平台上运行,并且在该工具下重现所有运行时情况并不总是可行或可行的。
cppcheck 1.77 and 1.49
> cat test.cc
#include <memory>
int main(){char* buf = new char[10];delete buf;}
http://cppcheck.sourceforge.net/
> cppcheck -x c++ test.cc
Checking test.cc ...
[test.cc:2]: (error) Mismatching allocation and deallocation: buf
clang++ 3.7.1
上RHEL7> clang++ --analyze -x c++ test.cc
test.cc:2:37: warning: Memory allocated by 'new[]' should be deallocated by
'delete[]', not 'delete'
int main(){char* buf = new char[10];delete buf;}
^~~~~~~~~~
1 warning generated.
Clang静态分析器还可以检测std::unique_ptr
未通过的时间<char[]>
> cat test2.cc
#include <memory>
int main(){std::unique_ptr<char> buf(new char[10]);}
https://clang-analyzer.llvm.org/
> clang++ --analyze -x c++ -std=c++11 test2.cc
In file included from test2.cc:1:
In file included from /opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/memory:81:
/opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/bits/unique_ptr.h:76:2:
warning: Memory allocated by
'new[]' should be deallocated by 'delete[]', not 'delete'
delete __ptr;
^~~~~~~~~~~~
1 warning generated.
在下面进行更新,并提供将其添加到clang的工作,测试和我发现的一个错误的链接。
这是通过reviews.llvm.org/D4661添加到clang的:“检测不匹配的'new'和'delete'用法”。
测试位于test / Analysis / MismatchedDeallocator-checker-test.mm中
我发现了此打开的错误-bugs.llvm.org/show_bug.cgi?id=24819