处理类 new 和删除运算符中的内存泄漏 C++

发布于 2025-01-05 06:34:49 字数 722 浏览 0 评论 0原文

我非常喜欢在 C++ 中使用运算符 newdelete,但稍后在程序代码中调用 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 字符串,但是当我删除它时,它会从 GUI 表单中删除该值,因为该字符串现已被删除。

有没有办法让我稍后以某种方式删除这个分配的字符串?

我不想将其声明为全局变量,然后在程序源代码的最后一行删除它。我永远不能调用delete,但据我所知,这是不好的,会导致内存泄漏。

I enjoy using the operators new and delete in C++ a lot but often have a problem calling delete later on in the program's code.

For example, in the following code:

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
}

I can declare a new string but when I delete it, it removes the value from the GUI form because that string has now been deleted.

Is there a way for me to delete this allocated string somehow later on?

I don't want to declare it as a global variable and then delete it on the last line of the program's source code. I could just never call delete but from what I have been taught that's bad and results in memory leaks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

你是我的挚爱i 2025-01-12 06:34:49

您应该阅读RAII 模式。它是 C++ 程序员需要了解的最重要的概念之一。

基本思想是资源(新建对象、HTTP 连接等)的生命周期与对象的生命周期相关。为了编写异常安全代码,这是必要的。

在您的情况下,UI 小部件将复制该对象并在其自己的析构函数中释放它。然后,调用代码可以立即释放其副本(在另一个析构函数中)。

You should read about the RAII pattern. It is one of the most important concepts to know for a C++ programmer.

The basic idea is that the lifetime of a resource (a new'ed object, an HTTP connection, etc.) is tied to the lifetime of an object. This is necessary in order to write exception safe code.

In your case, the UI widget would make a copy of the object and free it in its own destructor. The calling code could then free its copy right away (in another destructor).

回忆凄美了谁 2025-01-12 06:34:49

如果您为 aceui->label 使用 std::string 那么您不必担心内存一旦 foo 对象超出范围,foo->ace 就会被删除

Right-Hand 参数的副本可用于 = 上的 ui->label(赋值操作)。您可以在 C++ std::stringstring::operator= 的 code> 参考页。

此外,通过使用智能指针可以完全避免此类问题,例如 增强库。阅读关于此主题的 stackoverflow 上的这篇精彩文章,以获得更好的理解。

If you are using std::string for both ace and ui->label then you don't have to worry about the memory for foo->ace being deleted once the foo object goes out of scope.

A copy of the Right-Hand argument is made available to ui->label on an = (assignment operation). You can read more about it on the C++ std::string reference page for string::operator=.

Also, such problems can be avoided in full by using smart pointers, such as the ones provided by the boost library. Read this great post on stackoverflow on this subject to get a better understanding.

梦醒时光 2025-01-12 06:34:49

嗯,关于你的代码有很多话要说。有些事情已经说过了,例如,您应该使 string 成为普通成员,以便分配/解除分配问题完全消失(这是 C++ 程序的一般规则:如果您绝对必须使用动态分配,那就不要了,期间)。另外,使用适当的智能指针将为您进行内存管理(也是 C++ 中的一般规则:除非确实需要,否则不要自己管理动态分配)。

然而,让我们假设您必须使用动态分配,并且必须使用原始指针并在此处直接 newdelete 。然后另一个重要的规则出现了(这实际上不是 C++ 特定的规则,而是通用的 OO 规则):不要将成员公开。将其设置为私有成员,并提供公共成员函数进行设置。然后,该公共成员函数可以在将指针分配给新对象之前正确删除旧对象。请注意,一旦分配了指针,除非您已将旧值存储在其他地方,否则旧值将永远丢失,并且如果到目前为止该对象尚未删除,则以后将无法删除它。

您还需要考虑获取通过指针传递给您的对象的所有权是否真的是一个好主意(并分配给在析构函数中具有删除的指针成员 - 不是很明显― 传递所有权的方式)。这使对象生命周期管理变得复杂,因为您必须记住是否将某个对象传递给所有权声明对象(如果您有始终传递给所有权声明对象的严格策略,这不是问题, 尽管)。像往常一样,智能指针在这里可能会有所帮助;但是,您可能会考虑制作传递对象的副本是否是更好的选择(对于 std::string 来说肯定是,但是,如上所述,这里最好有一个直接成员多于)。

因此,这里有一个完整的规则列表,其中较早的规则优先于较晚的规则,除非有充分的理由不使用它:

  1. 不要使用动态分配。
  2. 使用智能指针管理动态分配。
  3. 仅在构造函数中使用 new ,仅在相应的析构函数中使用 delete
  4. 同一类的成员函数中始终具有特定指针的newdelete。 (实际上前一个规则是这个规则的一个特例,但是一个特例应该优先于一般规则。)

Well, there's a lot to say of your code. Some things have already been said, e.g. that you should make string a normal member so the allocation/deallcoation issue goes away completely (that's a general rule for C++ programs: If you don't absolutely have to use dynamic allocation, then don't, period). Also, using an appropriate smart pointer would do the memory management for you (also a general rule in C++: Don't manage the dynamic allocations yourself unless you really have to).

However let's pretend that you have to use dynamic allocation, and you have to use raw pointers and direct new and delete here. Then another important rule comes in (which actually isn't a C++ specific rule, but a general OO rule): Don't make the member public. Make it a private member, and offer a public member function for setting it. That public member function then can properly delete the old object before assigning the pointer to the new one. Note that as soon as you assigned the pointer, unless you've stored the old value elsewhere, the old value is lost forever, and if the object has not been deleted up to then, you can't delete it later.

You also want to consider whether it is really a good idea to take ownership of an object passed to you by pointer (and assigning to a pointer member which has a delete in the destructor is a ― not very obvious ― way to pass ownership). This complicates the object lifetime management because you have to remember whether you passed a certain object to an ownership-claiming object (this is not an issue if you have a strict policy of always passing to ownership-claiming objects, though). As usual, smart pointers may help here; however you may consider whether it is a better option to make a copy of the passed object (for std::string it definitely is, but then, here it's better to have a direct member anyway, as mentioned above).

So here's a full list of rules, where earlier rules take precedence to later unless there's a good reason not to use it:

  1. Don't use dynamical allocation.
  2. Manage your dynamical allocation with smart pointers.
  3. Use new only in constructors and delete only in the corresponding destructor.
  4. Always have the new and delete for a specific pointer in member functions of the same class. (Actually the previous rule is a special case of this one, but a special case which should be preferred to the general one.)
染火枫林 2025-01-12 06:34:49

这是一个更惯用的 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++ ;)

Here's a more idiomatic C++ program:

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
}

If you really need to call new, always use an appropriate smart pointer -- Writing delete is banished from modern C++ ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文