我如何*不*删除析构函数中的成员?

时间:2022-10-06 20:37:13

I'd like the destructor of my class to delete the entire object except for one of the members, which is deleted elsewhere. First of all, is this totally unreasonable? Assuming it's not, how do I do this? I thought that created an destructor with an empty body would prevent all the members from being deleted (because the destructor wouldn't do anything), but that doesn't seem to be the case.

我希望我的类的析构函数删除整个对象,除了其中一个成员,在其他地方删除。首先,这是完全不合理的吗?假设不是,我该怎么做?我认为创建一个带有空体的析构函数会阻止所有成员被删除(因为析构函数不会做任何事情),但似乎并非如此。

12 个解决方案

#1


Short answer: You don't.

简短的回答:你没有。

Longer answer: If the "member" is actually a pointer to some other allocation, you can arrange to not delete the other allocation.

更长的答案:如果“成员”实际上是指向其他一些分配的指针,则可以安排不删除其他分配。

But usually, if you allocated the other block in the constructor, you want to delete it in the destructor. Anything else will require careful handling of the "ownership" of the block in question. It will be a lot like memory management in plain c. Possible, but fraught with danger.

但通常,如果在构造函数中分配了另一个块,则需要在析构函数中删除它。其他任何事情都需要仔细处理相关区块的“所有权”。这很像普通c中的内存管理。可能,但充满危险。

Good luck.

#2


Depends on what you mean by "deleted". If they aren't in a smart pointer, and aren't explicitly deleted, then they aren't deleted. Members that are just part of the class:

取决于“删除”的含义。如果它们不在智能指针中,并且未明确删除,则不会删除它们。仅属于该课程的成员:

class Bar {
//...
private: 
  Foo foo;
};

Aren't deleted by the destructor (because they weren't dynamically allocated), they are just destroyed. They "live" inside the class, so once it is destroyed, it's gone.

不会被析构函数删除(因为它们没有动态分配),它们只是被销毁了。他们在课堂上“活着”,所以一旦它被摧毁,它就消失了。

If you are looking the share "ownership" between two locations, what you want is a dynamically allocated shared_ptr:

如果您正在查看两个位置之间的共享“所有权”,您想要的是动态分配的shared_ptr:

#include <memory>
class Bar {
// ...
private:
  std::tr1::shared_ptr<Foo> foo;
};

#3


If the member is contained by value (not by pointer or by reference) then you can't prevent it from being deleted and you shouldn't want to.

如果成员包含值(不是通过指针或引用),那么您无法阻止它被删除而您不应该这样做。

If you want to delete it elsewhere instead, then make it contained by pointer or by reference.

如果您想在其他地方删除它,请将其包含在指针或引用中。

class House
{
  Door door; //contained by value, will be destroyed when the House is
}

class House
{
  Door& door; //contained by reference, will not be destroyed when the House is
}

#4


The code in the destructor is only to delete members that are dynamically allocated. The destruction of members is not optional, you can only control the deallocation of what you explicitly allocated before (with operator new).

析构函数中的代码仅用于删除动态分配的成员。成员的销毁不是可选的,您只能控制之前显式分配的内容的释放(使用operator new)。

What you want to do can be obtained using a shared_ptr, in which both your class and the external code share a pointer to the same external object. This way, only when all the pointers to that object go out of scope it will be deleted. But beware not to do circular references, shared_ptr has no "garbage collector" wisdom.

您可以使用shared_ptr获取您想要做的事情,其中​​您的类和外部代码共享指向同一外部对象的指针。这样,只有当该对象的所有指针超出范围时,才会删除它。但要注意不要做循环引用,shared_ptr没有“垃圾收集器”的智慧。

Of course you could use a regular pointer shared by those places, but this is in most cases a bad idea, prone to give you headaches about proper resource deallocation later.

当然你可以使用这些地方共享的常规指针,但在大多数情况下这是一个坏主意,后来容易让你头疼关于正确的资源释放。

#5


First of all, if the member object is contained by value, it simply goes out of scope when the container object is destroyed, and you cannot prevent it from being deallocated automatically.

首先,如果成员对象是按值包含的,那么当容器对象被销毁时,它就会超出范围,并且无法阻止它自动释放。

If, instead, it is indirectly referenced by your container object (for example with a pointer), you don't have to do anything in particular to not delete it. The destructor doesn't delete anything unless you explicitly write the code to do so.

相反,如果它被容器对象间接引用(例如使用指针),则不必特别执行任何操作以不删除它。析构函数不会删除任何内容,除非您明确编写代码来执行此操作。

As for the question whether this is unreasonable, I think it is not, in general, but you have to make clear (usually in the documentation, since C++ has no language support for this concept) what is the object that owns the member in question.

至于这是否不合理的问题,我认为通常不是这样,但你必须明确(通常在文档中,因为C ++没有语言支持这个概念)拥有该成员的对象是什么。

#6


I think that in most cases you're asking for trouble if you don't destruct the entire object in the same action. It sounds like your class should have a clean up method for that member, which is called within the destructor. If for some reason the member has to be destroyed sooner, the method can return early.

我认为在大多数情况下,如果你不在同一个动作中破坏整个对象,你会遇到麻烦。听起来你的类应该为该成员提供一个清理方法,该方法在析构函数中调用。如果由于某种原因必须尽快销毁该成员,该方法可以提前返回。

#7


First of all, is this totally unreasonable?

首先,这是完全不合理的吗?

I wouldn't say unreasonable, perhaps questionable.

我不会说不合理,也许是可疑的。

It's perfectly valid for one class to own and therefore should take care of clean up, while at the same time having a reference or a pointer to that object in another class.

它对于一个类来说是完全有效的,因此应该注意清理,同时在另一个类中有一个引用或指向该对象的指针。

However, it might be questionable if the second class reall should have that pointer or not, I'd prefer to always use a get-method to retrieve that pointer whenever I need it, e.g. by calling a parent class or some resource manager.

但是,如果第二类reall应该有那个指针可能有问题,我宁愿总是使用get方法在我需要的时候检索指针,例如通过调用父类或某个资源管理器。

#8


If you have dynamically allocated memory for this member it is possible once you have shared the reference to this member before destroying the object and if you ensure the member is not destroyed in the object's destructor. However I think this practice isn't so reasonable.

如果为此成员动态分配了内存,则可以在销毁对象之前共享对此成员的引用,并确保在对象的析构函数中不销毁该成员。不过我觉得这种做法不太合理。

#9


When you talk about class members being deleted in the destructor, you have to make a distinction between members that are not pointers and those that are. Let's say you have a class like this:

当你谈论在析构函数中删除类成员时,你必须区分不是指针的成员和那些指针成员。假设你有一个这样的类:


class Foo
{
public:
  Foo() {p = new int;}
 ~Foo(){}

private:
 int a;
 int *p;
};

This class has 2 data members: an integer a and a pointer to an integer p. When the destructor is called, the object is destroyed, meaning that the destructors for all its members are called. This happens even if the destructor's body is empty. In the case of a primitive type, like an integer, calling its destructor just means that the memory it occupies will be released. However, there is a catch when you destroy a pointer: whatever it points to does not get destroyed by default. For that you have to explicitly call delete.

该类有2个数据成员:一个整数a和一个指向整数p的指针。调用析构函数时,对象将被销毁,这意味着将调用其所有成员的析构函数。即使析构函数的主体是空的,也会发生这种情况。在原始类型的情况下,如整数,调用它的析构函数只意味着它将占用的内存将被释放。但是,当你销毁一个指针时会有一个问题:它指向的任何东西都不会被默认销毁。为此,你必须明确地调用delete。

So in our example, a will be destroyed when the destructor is called, and so will p, but not whatever p points to. If you wish to free the memory to which p points, the destructor for Foo should look like this:

所以在我们的例子中,当析构函数被调用时,它将被销毁,p也将被销毁,但p指向的不是。如果你想释放p指向的内存,Foo的析构函数应如下所示:


~Foo() {delete p};

So, getting back to your question, all the members of your class which are not pointers will be destroyed no matter what, when the object's destructor is called. On the other hand, if you have members that are pointers, whatever they point to will not be destroyed, unless you specifically call delete for them in the destructor.

所以,回到你的问题,当你调用对象的析构函数时,你的类的所有不是指针的成员都将被销毁。另一方面,如果你有成员指针,他们指向的任何东西都不会被销毁,除非你在析构函数中专门为它们调用delete。

#10


How come no one mentioned weak and strong pointers?
A strong pointer is a smart pointer that acts normally.
A weak pointer is a smart pointer that cannot delete itself unless all of the strong pointers are out of scope.
Strong pointer indicates ownership, a weak pointer indicates sharing.
Look at boost.shared_ptr and boost.weak_ptr and Loki's StrongPtr for implementations.
Also take a look at RAII. If you knew RAII you would have known the answer to this question yourself.

怎么没有人提到弱点和强点?强指针是一个正常运行的智能指针。弱指针是一个智能指针,除非所有强指针都超出范围,否则它不能自行删除。强指针表示所有权,弱指针表示共享。查看boost.shared_ptr和boost.weak_ptr以及Loki的StrongPtr实现。另请参阅RAII。如果你知道RAII,你自己就会知道这个问题的答案。

#11


It is not unreasonable, but care should be taken to ensure that cleanup of any managed resources is handled implicitly.

这并非不合理,但应注意确保隐式处理任何托管资源的清理。

(The first managed resource that people generally worry about is memory, but anything that can leak - memory, file handles, IDispatch pointers - should have code which handles the cleanup implicitly).

(人们通常担心的第一个托管资源是内存,但任何可能泄漏的东西 - 内存,文件句柄,IDispatch指针 - 都应该有隐含处理清理的代码)。

For managed resources shared by multiple objects (almost certainly the case if "this object" is supposed to have a pointer to something that gets cleaned up by "that object"), you are normally needing either a "reference counted pointer" to manage the object or a "weak pointer", depending on your lifetime requirements.

对于由多个对象共享的托管资源(几乎可以肯定的是,如果“此对象”应该具有指向由“该对象”清理的内容的指针),则通常需要“引用计数指针”来管理对象或“弱指针”,取决于您的生命周期要求。

For managed resources which are not shared (and in particular those that need to be managed properly when exceptions can be thrown), then an auto_ptr or other variant may be more suitable.

对于未共享的托管资源(特别是那些在抛出异常时需要正确管理的资源),auto_ptr或其他变体可能更合适。

The Scott Meyers Effective C++ books were a reasonable starting point for learning about smart pointers, but in practice you should probably just grab a vetted library like Boost and let somebody else worry about getting the obscure corner cases (like what happens if a constructor throws an exception?) right.

Scott Meyers Effective C ++书籍是学习智能指针的合理出发点,但在实践中你应该只是抓住像Boost这样的经过审查的库,让其他人担心得到模糊的角落案例(如果构造函数抛出一个会发生什么例外?)对。

#12


This is possible but basically as @dmckee said it is then a ownership issue. If that is the case may be you can go for refcounting. i.e.

这是可能的,但基本上@dmckee说这是一个所有权问题。如果是这种情况可能是你可以去refcounting。即

class A
{

RefObj* obj;
A()
{

obj = new RefObj;

}

~A()
{
 obj->ReleaseRef();
}
}


RefObj
{

int m_iRefCounter;
RefObj()
{
m_iRefCounter = 1;
}
AddRef()
{
m_iRefCounter++;
}
ReleaseRef()
{
m_iRefCounter--
if(m_iRefCounter == 0)
{
 delete this;
}
}
}

}

#1


Short answer: You don't.

简短的回答:你没有。

Longer answer: If the "member" is actually a pointer to some other allocation, you can arrange to not delete the other allocation.

更长的答案:如果“成员”实际上是指向其他一些分配的指针,则可以安排不删除其他分配。

But usually, if you allocated the other block in the constructor, you want to delete it in the destructor. Anything else will require careful handling of the "ownership" of the block in question. It will be a lot like memory management in plain c. Possible, but fraught with danger.

但通常,如果在构造函数中分配了另一个块,则需要在析构函数中删除它。其他任何事情都需要仔细处理相关区块的“所有权”。这很像普通c中的内存管理。可能,但充满危险。

Good luck.

#2


Depends on what you mean by "deleted". If they aren't in a smart pointer, and aren't explicitly deleted, then they aren't deleted. Members that are just part of the class:

取决于“删除”的含义。如果它们不在智能指针中,并且未明确删除,则不会删除它们。仅属于该课程的成员:

class Bar {
//...
private: 
  Foo foo;
};

Aren't deleted by the destructor (because they weren't dynamically allocated), they are just destroyed. They "live" inside the class, so once it is destroyed, it's gone.

不会被析构函数删除(因为它们没有动态分配),它们只是被销毁了。他们在课堂上“活着”,所以一旦它被摧毁,它就消失了。

If you are looking the share "ownership" between two locations, what you want is a dynamically allocated shared_ptr:

如果您正在查看两个位置之间的共享“所有权”,您想要的是动态分配的shared_ptr:

#include <memory>
class Bar {
// ...
private:
  std::tr1::shared_ptr<Foo> foo;
};

#3


If the member is contained by value (not by pointer or by reference) then you can't prevent it from being deleted and you shouldn't want to.

如果成员包含值(不是通过指针或引用),那么您无法阻止它被删除而您不应该这样做。

If you want to delete it elsewhere instead, then make it contained by pointer or by reference.

如果您想在其他地方删除它,请将其包含在指针或引用中。

class House
{
  Door door; //contained by value, will be destroyed when the House is
}

class House
{
  Door& door; //contained by reference, will not be destroyed when the House is
}

#4


The code in the destructor is only to delete members that are dynamically allocated. The destruction of members is not optional, you can only control the deallocation of what you explicitly allocated before (with operator new).

析构函数中的代码仅用于删除动态分配的成员。成员的销毁不是可选的,您只能控制之前显式分配的内容的释放(使用operator new)。

What you want to do can be obtained using a shared_ptr, in which both your class and the external code share a pointer to the same external object. This way, only when all the pointers to that object go out of scope it will be deleted. But beware not to do circular references, shared_ptr has no "garbage collector" wisdom.

您可以使用shared_ptr获取您想要做的事情,其中​​您的类和外部代码共享指向同一外部对象的指针。这样,只有当该对象的所有指针超出范围时,才会删除它。但要注意不要做循环引用,shared_ptr没有“垃圾收集器”的智慧。

Of course you could use a regular pointer shared by those places, but this is in most cases a bad idea, prone to give you headaches about proper resource deallocation later.

当然你可以使用这些地方共享的常规指针,但在大多数情况下这是一个坏主意,后来容易让你头疼关于正确的资源释放。

#5


First of all, if the member object is contained by value, it simply goes out of scope when the container object is destroyed, and you cannot prevent it from being deallocated automatically.

首先,如果成员对象是按值包含的,那么当容器对象被销毁时,它就会超出范围,并且无法阻止它自动释放。

If, instead, it is indirectly referenced by your container object (for example with a pointer), you don't have to do anything in particular to not delete it. The destructor doesn't delete anything unless you explicitly write the code to do so.

相反,如果它被容器对象间接引用(例如使用指针),则不必特别执行任何操作以不删除它。析构函数不会删除任何内容,除非您明确编写代码来执行此操作。

As for the question whether this is unreasonable, I think it is not, in general, but you have to make clear (usually in the documentation, since C++ has no language support for this concept) what is the object that owns the member in question.

至于这是否不合理的问题,我认为通常不是这样,但你必须明确(通常在文档中,因为C ++没有语言支持这个概念)拥有该成员的对象是什么。

#6


I think that in most cases you're asking for trouble if you don't destruct the entire object in the same action. It sounds like your class should have a clean up method for that member, which is called within the destructor. If for some reason the member has to be destroyed sooner, the method can return early.

我认为在大多数情况下,如果你不在同一个动作中破坏整个对象,你会遇到麻烦。听起来你的类应该为该成员提供一个清理方法,该方法在析构函数中调用。如果由于某种原因必须尽快销毁该成员,该方法可以提前返回。

#7


First of all, is this totally unreasonable?

首先,这是完全不合理的吗?

I wouldn't say unreasonable, perhaps questionable.

我不会说不合理,也许是可疑的。

It's perfectly valid for one class to own and therefore should take care of clean up, while at the same time having a reference or a pointer to that object in another class.

它对于一个类来说是完全有效的,因此应该注意清理,同时在另一个类中有一个引用或指向该对象的指针。

However, it might be questionable if the second class reall should have that pointer or not, I'd prefer to always use a get-method to retrieve that pointer whenever I need it, e.g. by calling a parent class or some resource manager.

但是,如果第二类reall应该有那个指针可能有问题,我宁愿总是使用get方法在我需要的时候检索指针,例如通过调用父类或某个资源管理器。

#8


If you have dynamically allocated memory for this member it is possible once you have shared the reference to this member before destroying the object and if you ensure the member is not destroyed in the object's destructor. However I think this practice isn't so reasonable.

如果为此成员动态分配了内存,则可以在销毁对象之前共享对此成员的引用,并确保在对象的析构函数中不销毁该成员。不过我觉得这种做法不太合理。

#9


When you talk about class members being deleted in the destructor, you have to make a distinction between members that are not pointers and those that are. Let's say you have a class like this:

当你谈论在析构函数中删除类成员时,你必须区分不是指针的成员和那些指针成员。假设你有一个这样的类:


class Foo
{
public:
  Foo() {p = new int;}
 ~Foo(){}

private:
 int a;
 int *p;
};

This class has 2 data members: an integer a and a pointer to an integer p. When the destructor is called, the object is destroyed, meaning that the destructors for all its members are called. This happens even if the destructor's body is empty. In the case of a primitive type, like an integer, calling its destructor just means that the memory it occupies will be released. However, there is a catch when you destroy a pointer: whatever it points to does not get destroyed by default. For that you have to explicitly call delete.

该类有2个数据成员:一个整数a和一个指向整数p的指针。调用析构函数时,对象将被销毁,这意味着将调用其所有成员的析构函数。即使析构函数的主体是空的,也会发生这种情况。在原始类型的情况下,如整数,调用它的析构函数只意味着它将占用的内存将被释放。但是,当你销毁一个指针时会有一个问题:它指向的任何东西都不会被默认销毁。为此,你必须明确地调用delete。

So in our example, a will be destroyed when the destructor is called, and so will p, but not whatever p points to. If you wish to free the memory to which p points, the destructor for Foo should look like this:

所以在我们的例子中,当析构函数被调用时,它将被销毁,p也将被销毁,但p指向的不是。如果你想释放p指向的内存,Foo的析构函数应如下所示:


~Foo() {delete p};

So, getting back to your question, all the members of your class which are not pointers will be destroyed no matter what, when the object's destructor is called. On the other hand, if you have members that are pointers, whatever they point to will not be destroyed, unless you specifically call delete for them in the destructor.

所以,回到你的问题,当你调用对象的析构函数时,你的类的所有不是指针的成员都将被销毁。另一方面,如果你有成员指针,他们指向的任何东西都不会被销毁,除非你在析构函数中专门为它们调用delete。

#10


How come no one mentioned weak and strong pointers?
A strong pointer is a smart pointer that acts normally.
A weak pointer is a smart pointer that cannot delete itself unless all of the strong pointers are out of scope.
Strong pointer indicates ownership, a weak pointer indicates sharing.
Look at boost.shared_ptr and boost.weak_ptr and Loki's StrongPtr for implementations.
Also take a look at RAII. If you knew RAII you would have known the answer to this question yourself.

怎么没有人提到弱点和强点?强指针是一个正常运行的智能指针。弱指针是一个智能指针,除非所有强指针都超出范围,否则它不能自行删除。强指针表示所有权,弱指针表示共享。查看boost.shared_ptr和boost.weak_ptr以及Loki的StrongPtr实现。另请参阅RAII。如果你知道RAII,你自己就会知道这个问题的答案。

#11


It is not unreasonable, but care should be taken to ensure that cleanup of any managed resources is handled implicitly.

这并非不合理,但应注意确保隐式处理任何托管资源的清理。

(The first managed resource that people generally worry about is memory, but anything that can leak - memory, file handles, IDispatch pointers - should have code which handles the cleanup implicitly).

(人们通常担心的第一个托管资源是内存,但任何可能泄漏的东西 - 内存,文件句柄,IDispatch指针 - 都应该有隐含处理清理的代码)。

For managed resources shared by multiple objects (almost certainly the case if "this object" is supposed to have a pointer to something that gets cleaned up by "that object"), you are normally needing either a "reference counted pointer" to manage the object or a "weak pointer", depending on your lifetime requirements.

对于由多个对象共享的托管资源(几乎可以肯定的是,如果“此对象”应该具有指向由“该对象”清理的内容的指针),则通常需要“引用计数指针”来管理对象或“弱指针”,取决于您的生命周期要求。

For managed resources which are not shared (and in particular those that need to be managed properly when exceptions can be thrown), then an auto_ptr or other variant may be more suitable.

对于未共享的托管资源(特别是那些在抛出异常时需要正确管理的资源),auto_ptr或其他变体可能更合适。

The Scott Meyers Effective C++ books were a reasonable starting point for learning about smart pointers, but in practice you should probably just grab a vetted library like Boost and let somebody else worry about getting the obscure corner cases (like what happens if a constructor throws an exception?) right.

Scott Meyers Effective C ++书籍是学习智能指针的合理出发点,但在实践中你应该只是抓住像Boost这样的经过审查的库,让其他人担心得到模糊的角落案例(如果构造函数抛出一个会发生什么例外?)对。

#12


This is possible but basically as @dmckee said it is then a ownership issue. If that is the case may be you can go for refcounting. i.e.

这是可能的,但基本上@dmckee说这是一个所有权问题。如果是这种情况可能是你可以去refcounting。即

class A
{

RefObj* obj;
A()
{

obj = new RefObj;

}

~A()
{
 obj->ReleaseRef();
}
}


RefObj
{

int m_iRefCounter;
RefObj()
{
m_iRefCounter = 1;
}
AddRef()
{
m_iRefCounter++;
}
ReleaseRef()
{
m_iRefCounter--
if(m_iRefCounter == 0)
{
 delete this;
}
}
}

}