How do I *not* delete a member in a destructor?
Asked Answered
L

12

7

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.

Lona answered 6/7, 2009 at 17:30 Comment(1)
A short code example would be useful.Snitch
O
15

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.

Good luck.

Osteoclasis answered 6/7, 2009 at 17:34 Comment(0)
S
10

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:

#include <memory>
class Bar {
// ...
private:
  std::tr1::shared_ptr<Foo> foo;
};
Smock answered 6/7, 2009 at 17:34 Comment(0)
V
4

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
}
Vaticinate answered 6/7, 2009 at 17:35 Comment(4)
BUt if I nock down your house, I expect the door to be destroyed in the rubble.Sam
That's because the door's usually contained by value within the house. If instead of 'House' and 'Door' it were 'Order' and 'Customer', cancelling an order typically shouldn't destroy the associated customer.Vaticinate
@Martin York Yes but you don't go to my fridge first, find a sticker with the address of the roast chicken shop around the corner, and then destroy it too, in the process of destroying my house.Janitajanith
@Daniel The sticker on the roast chicken is a 'weak' reference: the chicken knows the store but doesn't own it. The roast chicken might actually have a reference-counted reference though, so that the store is garbage-collected automatically when the last of its roast chickens is consumed.Vaticinate
U
3

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).

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.

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.

Unfledged answered 6/7, 2009 at 17:37 Comment(0)
D
2

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.

Dance answered 6/7, 2009 at 17:53 Comment(0)
D
1

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.

Deledda answered 6/7, 2009 at 17:35 Comment(0)
T
0

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.

Troytroyer answered 6/7, 2009 at 17:36 Comment(0)
B
0

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.

Brindle answered 6/7, 2009 at 17:37 Comment(0)
B
0

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.

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:


~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.

Blondell answered 6/7, 2009 at 17:45 Comment(0)
T
0

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.

Tradein answered 6/7, 2009 at 17:53 Comment(2)
Nobody mentioned weak and strong pointers, because the question is at a very basic level of C++.Blondell
So maybe it's his time to advance a bit.Tradein
T
0

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).

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.

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.

Testament answered 6/7, 2009 at 18:20 Comment(0)
C
0

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.

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;
}
}
}

}

Chilung answered 28/11, 2010 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.