删除指针内存并确认
Delete pointer memory and confirm it
考虑以下因素:
tbModelHFrame = new TbModelHeaderFrame(this, storage->getDataBase());
我想删除 tbModelHFrame 内存的正确方法是
delete tbModelHFrame;
对吗?
如何查看内存是否真的释放了?
是的,用 new
分配的应该用 delete
释放。
检查每个动态分配的内存是否已被释放的方法是使用 Valgrind 的 Memcheck
无论如何,通常使用智能指针更安全(See here)。
How do I check that the memory was really released?
你不知道。
C++ 无法判断指针是指向有效对象还是指向内存中的随机区域。后者包括一个在某个时候有效但此后已被删除的区域。
开发人员应该以一种不会发生这种情况的方式来组织他们的代码。
语言为您提供帮助的唯一保证是 delete
调用永远不会失败。所以如果你在对象上调用一次 delete
,你可以合理地确定对象被正确销毁并且内存被释放。只是以后不要尝试再次访问它,否则你会有麻烦。
根据删除运算符reference:
[..] In all cases, if ptr is a null pointer, the standard library
deallocation functions do nothing.
If the pointer passed to the
standard library deallocation function was not obtained from the
corresponding standard library allocation function, the behavior is
undefined.
After the standard library deallocation function returns,
all pointers referring to any part of the deallocated storage become
invalid.
Any use of a pointer that became invalid in this manner, even
copying the pointer value into another variable, is undefined
behavior. (until C++14)
Indirection through a pointer that became
invalid in this manner and passing it to a deallocation function
(double-delete) is undefined behavior. Any other use is
implementation-defined.
因此,如果删除指针出现问题,则为未定义行为。
问题的前提是错误的:如果delete
不释放内存,你的堆已经损坏,你的应用程序已经可以做任何事情,包括格式化你的硬盘。因此,如果涉及到这一点,您遇到的问题不仅仅是 delete
是空操作。所以,别担心。只要没有因为您自己的代码中的内存错误而弄乱您的堆,就可以了。
无论如何,你不应该使用裸指针作为拥有指针。这是C++,不是C。
使用智能指针:
QScopedPointer<TbModelHeaderFrame> tbModelHFrame(
new TbModelHeaderFrame(this, storage->getDataBase())
);
...
tbModelHFrame->something(); // do something with it
就是这样。当指针超出范围时,内存将被释放。你不用担心。
指针也可以是class成员:
class Foo {
QScopedPointer<TbModelHeaderFrame> m_modelHFrame;
...
};
Foo::Foo() :
m_modelHFrame(new TbModelHeaderFrame(this, storage->getDataBase())) {
...
}
或
Foo::Foo() : ... {
m_modelHFrame.reset(new TbModelHeaderFrame(this, storage->getDataBase()));
...
}
现代 C++ 代码应设计为不使用手动内存管理,除非出于众所周知的原因绝对必要。在大多数情况下,现代 C++ 中的裸指针和手动内存管理是糟糕设计的标志,而不是必要的。
TL;DR:现代 C++/Qt 代码可以而且应该读起来有点像 Python :)
考虑以下因素:
tbModelHFrame = new TbModelHeaderFrame(this, storage->getDataBase());
我想删除 tbModelHFrame 内存的正确方法是
delete tbModelHFrame;
对吗?
如何查看内存是否真的释放了?
是的,用 new
分配的应该用 delete
释放。
检查每个动态分配的内存是否已被释放的方法是使用 Valgrind 的 Memcheck
无论如何,通常使用智能指针更安全(See here)。
How do I check that the memory was really released?
你不知道。
C++ 无法判断指针是指向有效对象还是指向内存中的随机区域。后者包括一个在某个时候有效但此后已被删除的区域。
开发人员应该以一种不会发生这种情况的方式来组织他们的代码。
语言为您提供帮助的唯一保证是 delete
调用永远不会失败。所以如果你在对象上调用一次 delete
,你可以合理地确定对象被正确销毁并且内存被释放。只是以后不要尝试再次访问它,否则你会有麻烦。
根据删除运算符reference:
[..] In all cases, if ptr is a null pointer, the standard library deallocation functions do nothing.
If the pointer passed to the standard library deallocation function was not obtained from the corresponding standard library allocation function, the behavior is undefined.
After the standard library deallocation function returns, all pointers referring to any part of the deallocated storage become invalid.
Any use of a pointer that became invalid in this manner, even copying the pointer value into another variable, is undefined behavior. (until C++14)
Indirection through a pointer that became invalid in this manner and passing it to a deallocation function (double-delete) is undefined behavior. Any other use is implementation-defined.
因此,如果删除指针出现问题,则为未定义行为。
问题的前提是错误的:如果delete
不释放内存,你的堆已经损坏,你的应用程序已经可以做任何事情,包括格式化你的硬盘。因此,如果涉及到这一点,您遇到的问题不仅仅是 delete
是空操作。所以,别担心。只要没有因为您自己的代码中的内存错误而弄乱您的堆,就可以了。
无论如何,你不应该使用裸指针作为拥有指针。这是C++,不是C。
使用智能指针:
QScopedPointer<TbModelHeaderFrame> tbModelHFrame(
new TbModelHeaderFrame(this, storage->getDataBase())
);
...
tbModelHFrame->something(); // do something with it
就是这样。当指针超出范围时,内存将被释放。你不用担心。
指针也可以是class成员:
class Foo {
QScopedPointer<TbModelHeaderFrame> m_modelHFrame;
...
};
Foo::Foo() :
m_modelHFrame(new TbModelHeaderFrame(this, storage->getDataBase())) {
...
}
或
Foo::Foo() : ... {
m_modelHFrame.reset(new TbModelHeaderFrame(this, storage->getDataBase()));
...
}
现代 C++ 代码应设计为不使用手动内存管理,除非出于众所周知的原因绝对必要。在大多数情况下,现代 C++ 中的裸指针和手动内存管理是糟糕设计的标志,而不是必要的。
TL;DR:现代 C++/Qt 代码可以而且应该读起来有点像 Python :)