处理类 new 和删除运算符中的内存泄漏 C++
Dealing with memory leaks in class new and delete operators C++
我喜欢使用运算符new
和delete
C++,但后来在程序代码中调用delete
时经常遇到问题。
例如,在下面的代码中:
class Foo {
public:
string *ace;
Foo();
~Foo();
};
Foo::Foo() {
ace = new string;
}
Foo::~Foo() {
delete ace;
}
void UI::ButtonPressed() { //Happens when an event is triggered
Foo *foo = new Foo;
ui->label = ace; //Set some text on the GUI
delete foo; //Calls the destructor, deleting "ace" and removing it from the GUI window
}
我可以声明一个new
字符串,但是当我delete
它时,它会从 GUI 表单中删除该值,因为该字符串现已被删除。
以后有没有办法以某种方式删除这个分配的字符串?
我不想将其声明为全局变量,然后将其delete
在程序源代码的最后一行。我永远不能打电话给delete
但从我所学到的,这很糟糕,会导致内存泄漏。
您应该阅读有关 RAII 模式的信息。对于C++程序员来说,这是最重要的概念之一。
基本思想是资源(新对象、HTTP 连接等(的生存期与对象的生存期相关联。这是编写异常安全代码所必需的。
在您的情况下,UI 小部件将创建对象的副本,并在其自己的析构函数中释放它。然后,调用代码可以立即释放其副本(在另一个析构函数中(。
如果您同时将std::string
用于ace
和ui->label
,那么您不必担心一旦foo
对象超出范围,foo->ace
的内存就会被delete
。
右手参数的副本可用于=
ui->label
(赋值操作(。您可以在C++ std::string
参考页面上阅读有关它的更多信息,以获取string::operator=
。
此外,通过使用智能指针(例如 boost 库提供的指针(可以完全避免此类问题。阅读这篇关于这个主题的关于stackoverflow的好文章,以获得更好的理解。
好吧,你的代码有很多话要说。有些事情已经说过了,例如,你应该让字符串成为普通成员,这样分配/去allcoation问题就完全消失了(这是C++程序的一般规则:如果你不是绝对必须使用动态分配,那就不要,句号(。此外,使用适当的智能指针将为您进行内存管理(也是C++中的一般规则:除非确实必须,否则不要自己管理动态分配(。
但是,让我们假设您必须使用动态分配,并且必须在此处使用原始指针和直接new
和delete
。然后另一个重要的规则进来了(实际上不是C++特定的规则,而是一般的OO规则(:不要公开成员。使其成为私有成员,并提供用于设置它的公共成员功能。然后,该公共成员函数可以在将指针分配给新对象之前正确删除旧对象。请注意,一旦您分配了指针,除非您已将旧值存储在其他位置,否则旧值将永远丢失,如果在此之前尚未删除该对象,则以后无法删除它。
您还需要考虑获取通过指针传递给您的对象的所有权是否真的是一个好主意(并且分配给在析构函数中具有删除的指针成员是一种传递所有权的方式(不是很明显(。这使对象生存期管理复杂化,因为您必须记住是否将某个对象传递给所有权声明对象(但是,如果您有始终传递给所有权声明对象的严格策略,这不是问题(。像往常一样,智能指针可能会在这里有所帮助;但是,您可以考虑复制传递的对象是否是一个更好的选择(std::string
肯定是这样,但是,无论如何最好有一个直接成员,如上所述(。
因此,这里有一个完整的规则列表,其中较早的规则优先于较晚的规则,除非有充分的理由不使用它:
- 不要使用动态分配。
- 使用智能指针管理动态分配。
- 仅在构造函数中使用
new
,仅在相应的析构函数中使用delete
。 - 始终具有同一类的成员函数中特定指针的
new
和delete
。 (实际上,前面的规则是此规则的特例,但是一种特殊情况,应该优先于一般规则。
这是一个更惯用的C++程序:
class Foo {
public:
std::string ace;
Foo() : ace() {
// nothing to do here. ace knows how to create itself…
}
// and copy itself…
Foo(const Foo& other) : ace(other.ace) {}
// and clean up after itself…
~Foo() {
}
// and copy/assign itself…
Foo& operator=(const Foo& other) {
this->ace = other.ace;
return *this;
}
};
void UI::ButtonPressed() {
// `new` is not needed here, either!
Foo foo;
ui->label = foo.ace; //Set some text on the GUI
// `delete` is not needed here
}
如果你真的需要调用new
,请始终使用适当的智能指针 - 写入delete
被从现代C++ ;)中驱逐
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 尽管遵循了规则,内存泄漏在哪里
- 为什么调用堆栈数组会导致内存泄漏
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 使用模板类的自定义列表类型中的内存泄漏
- 为什么以下C++代码中存在内存泄漏?
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 我是否生成线程并导致内存泄漏?
- 多线程程序中出现意外的内存泄漏
- 为什么此函数会导致内存泄漏?
- 在 C++ 库中使用cythonized python时内存泄漏
- 需要帮助查找内存泄漏
- 瓦尔格林德的内存泄漏使用新的
- 无法找出我的代码中的内存泄漏
- C++ 结构内部的unordered_map会导致内存泄漏问题吗?
- 可视化 使用 VS Code 查找C++应用程序中的内存泄漏
- Shared_ptr双链接列表内存泄漏
- C++ 在类中使用常量引用文本时 O2 内存泄漏