删除以 void 指针作为成员的嵌套结构?

发布于 2024-09-11 00:43:17 字数 846 浏览 9 评论 0原文

我有以下类:

class Stack {
  struct Link {
    void* data;
    Link* next;
    void initialize(void* dat, Link* nxt);
  }* head;
public:
  void initialize();
  void push(void* dat);
  void* peek();
  void* pop();
  void cleanup();
};

pop 方法是:

void* Stack::pop() {
  if(head == 0) return 0;
  void* result = head->data;
  Link* oldHead = head;
  head = head->next;
  delete oldHead;
  return result;
}

oldHead 是指向 struct Link 的指针,该结构有一个 void 指针作为成员。因此,通过删除 oldHead 我就隐式删除了该 void 指针,对吗?

我正在阅读 Bruce Eckel 的《Thinking in C++》,它说删除 void 指针并不能正确清理问题,因为 delete 需要知道指针的类型。

此代码隐式删除 void 指针 data,因此:有人可以解释一下为什么这种删除 void 指针的(隐式)方式与使用 delete 删除不同>?

I have the following class:

class Stack {
  struct Link {
    void* data;
    Link* next;
    void initialize(void* dat, Link* nxt);
  }* head;
public:
  void initialize();
  void push(void* dat);
  void* peek();
  void* pop();
  void cleanup();
};

The pop method is:

void* Stack::pop() {
  if(head == 0) return 0;
  void* result = head->data;
  Link* oldHead = head;
  head = head->next;
  delete oldHead;
  return result;
}

oldHead is a pointer to a struct Link, which has a void pointer as member. So by deleting oldHead I'm implicitly deleting that void pointer, right?

I'm reading Thinking in C++ by Bruce Eckel, and it says that deleting void pointers doesn't clean things up properly because delete needs to know the type of the pointer.

This code is implicitly deleting the void pointer data, so: Can someone explain why is this (implicit) way of deleting a void pointer different from deleting with delete <void pointer>?

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

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

发布评论

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

评论(4

貪欢 2024-09-18 00:43:17

您的术语引起了歧义,但让我解释一下。假设您有:

struct foo
{
    void* bar;
};

每当 foo 结束其生命周期时,bar 也会停止存在。因此,如果您有:

{
    foo f = { new int; }
}

您已经泄漏了,因为 new int 永远不会被删除。同样,当你这样做时:

{
    foo* f = new foo;
    f->bar = new int;
    delete f;
}

你仍然泄漏了,因为当运行 delete f 时,你只是结束了 f 所指向的生命周期(就像自动发生的那样)上面),因此 bar 不再存在,并且 new int 不会被删除。

总而言之,当对象的生命周期结束时,不会对指针成员调用delete

因此,当您在 Link 上调用 delete 时,与上面 foo 中的 bar 的情况相同:您正在删除 Link 的内存>Link 导致 data 停止存在,但实际上并没有删除它所指向的内容。

Your terminology is causing ambiguity, but let me explain. Let's say you have:

struct foo
{
    void* bar;
};

Whenever a foo ends its lifetime, bar simply stops existing too. So if you have:

{
    foo f = { new int; }
}

You've leaked, as new int is never deleted. Likewise, when you do:

{
    foo* f = new foo;
    f->bar = new int;
    delete f;
}

You've still leaked, since when delete f is run, you simply end the lifetime of what f is pointing to (just like what happened automatically above), ergo bar simply ceases to exist and the new int is not deleted.

To summarize, when an object's lifetimes ends, delete is not called on the members that are a pointer.

So when you call delete on a Link, it's the same situation as bar in foo above: you're deleteing the memory for a Link causing data to stop existing, but not actually deleting what it's pointing at.

撩起发的微风 2024-09-18 00:43:17

通过删除 Link,该 void* 内存空间不会被删除。您需要定义一个析构函数来删除已分配的内存。每个新的都需要一个删除。链接结构的一个示例是添加一个删除数据的析构函数。如果您的假设是正确的,那么 next 也会被删除,导致整个链接列表被删除,这将是一个可怕的行为。

对指针调用delete将调用所指向类型的析构函数。如果该类型没有析构函数,则不会调用此类析构函数。这是没有析构函数的 void 指针的情况。在继承的情况下,析构函数应该始终是虚拟的,以便层次结构中最深的类将调用其析构函数。即使您将指针转换为错误的类型,内存也会被正确释放 - 只是析构函数将被错误地调用。

By deleting Link, that void* memory space is not being deleted. You need to define a destructor which deletes the memory that has been allocated. Each new needs one delete. An example of this for the Link-struct would be to add a destructor that deletes data. If your assumption would be correct, then next would also be deleted, causing your entire linked-list to be deleted which would be a terrible behavior.

Calling delete on a pointer will call the destructor of the pointed to type. If that type has no destructor, no such destructor will be called. This is the case for a void pointer which doesn't have a destructor. In the case of inheritance, the destructor should always be virtual so that the deepest class in the hierarchy will have their destructor called. The memory will be correctly free'd even if you cast your pointers to the wrong types - it's just that the destructor will be called incorrectly.

转身泪倾城 2024-09-18 00:43:17

“我正在隐式删除该 void 指针,对吗?”

好吧,当您删除 oldHead 时,您正在删除指针本身。您没有删除或释放其目标,这似乎是您想要的,并且是在指针上调用delete时发生的情况。

(要了解为什么会出现这种情况,请考虑您可能会定义一个带有指向该结构之外的内容的 void* 指针的结构。您不希望仅仅因为该结构就释放目标已被删除。)

"I'm implicitly deleting that void pointer, right?"

Well, you're deleting the pointer itself when you delete oldHead. You're not deleting or freeing its target, which is what you seem to be wanting, and is what happens when you call delete on a pointer.

(To see why this is the case, consider that you might define a struct with a void* pointer that points to something outside the struct. You wouldn't want the target to be freed just because the struct was deleted.)

无人问我粥可暖 2024-09-18 00:43:17

当您使用析构函数指向某个对象时,删除 void 指针会出现一个问题:

#include <iostream>

struct foo
{
    ~foo() { std::cout << "important work" << std::endl; }
};

int main()
{
    foo *f = new foo;

    void *v = f;

    delete v;
}

如果运行上面的代码示例,您将看到析构函数从未被调用。

One problem with deleting a void pointer happens when you are pointing to something with a destructor:

#include <iostream>

struct foo
{
    ~foo() { std::cout << "important work" << std::endl; }
};

int main()
{
    foo *f = new foo;

    void *v = f;

    delete v;
}

If you run the code sample above, you will see that the destructor is never called.

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