Destructor and default destructor

Pages: 12
Thanks to all.

On those 7 methods of a class whether some/none or all of them are needed, is there any simple standard approach using it we know for what type of class we need what method, or is it achievable only by experience?
Also, is it true that smart pointers in C++ are preferable to raw pointers only in exceptions? That is, the only needed use of smart pointers is for exceptions.
No, it is not true. Smart pointers are very useful even if you don't use exceptions.
No, that is not true.

If you're doing any kind of heap memory allocation, smart pointers are preferable to raw pointers basically always.

Not using pointers at all is preferable to any kind of pointer basically always (i.e. don't use pointers at all when you don't have to).

If I had to guess, you've seen a situation in which smart pointers are very very helpful, and mistaken it for the only use case.

Here, look at this code:
1
2
3
4
5
6
7
8
9
void someFunction()
{
  BigObject* p = new BigPObject;

  // LOTS AND LOTS OF CODE HERE

  delete p;
  return;
}


What happens if, somewhere in all that LOTS AND LOTS, an exception is thrown? Memory leak. delete p; would never get called.

We could try something like this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void someFunction()
{
  BigObject* p = new BigPObject;

  try
  {
    // LOTS AND LOTS OF CODE HERE
  }
  catch (someException& e) 
  {
    delete p;
    throw e;
  }

  delete p;
  return;
}


that is, catch any exceptions that are thrown, delete the object, and then throw the exception again. Yuck! This would mean we have to catch every possible kind of exception here, and then we just rethrow it! What if we forget one, or the code changes and there's a new one. Oh, this is just far too fragile. Or we could have a catch (...) there and catch completely everything. It's still pretty ugly.

But what if we did this:
1
2
3
4
5
6
7
8
void someFunction()
{
  unique_ptr<BigObject> p = make_unique<BigObject>();

   // LOTS AND LOTS OF CODE HERE
  
  return;
}


Done. There is no way to return from this function without that memory being tidied up. Return anywhere you like, throw any exception you like, doesn't matter. No leak, now and always.

So that's what I think you saw. You saw that smart pointers completely solve this problem of an exception throw skipping memory tidy-up at the end of a function, and mistook it for the only case where smart pointers help.
Last edited on
Thank you guys. then if smart C++ pointers are preferable to raw pointers in all situations allocating memory dynamically, that's exactly what I thought and still think.

One question, are you familiar with Qt? If so please join me in another forum where people their are downplaying smart pointers in favor of Qt parent-child relation.

Do you like to take a look there and if possible have some answers there too?
Last edited on
A "smart pointer" is an object that manages dynamically allocated memory on your behalf.
The std::vector is an object that manages dynamically allocated memory on your behalf.
Those Qt objects manage dynamically allocated memory on your behalf.

Forget rigid "all situations" rules learn the object types that you have to work with/choose from.
My standpoint was that, in Qt, a child created dynamically is deleted, freeing memory, when its parent is deleted, normally. But I say there might be situations where we close a child and continue with the parent. Then those resources are waiting to be freed (leak) until the parent closes.
That is not a leak. You can still access the object via its parent and the parent will destroy the object orderly.

A leak is allocated memory that you cannot refer to any more.

There is QObject::deleteLater() to kill a child sooner. However, if your program spawns endless children during the lifetime of a parent, then you should check your design and consider alternative approaches.
Just wanted to say: GUI frameworks can be a separate category of beasts, and you'd have to read the documentation and best practices of the framework you're using before assuming anything.

wxWidgets (another, open source GUI framework) uses macro magic to create some of its structure, and internally handles cleaning up child windows/widgets, so only rarely would the user have to delete anything, despite the fact that you'll probably often say new MyWxWidgetsObject(parent).
@frek,

You will find some "niche" type opinions that get deep seated. Qt users have such a following and can be a tad fanatical IMNSHO.

Qt had "solutions" pre-dating the C++ standard for smart pointers.
@keskiverto and others

A scenario I have in mind is that we gain some memory dynamically and when we're done with it, we don't release the resource immediately. For example consider a web browser as our project, with a + button for creating new tabs.

Using smart pointers: Each new instance of the main window of the browser is created using a smart pointer each time the + button is pressed. In the morning (8:00 o'clock), we start our program and go on google .com. Then in the space of one hour we open 20 new tabs for investigating a specific matter, while our main window, google .com is still open. At 9:00 o'clock, we close all other tabs and continue working only on google .com using the info we've gained previously, until midday, 13:00.
Conclusion: we have no memory leak because when at 9:00 o'clock we closed other tabs, by each close the smart pointer used for that tab calls its destructor and frees the resource.

Using parent-child relation and raw pointers: Consider the exactly same scenario but with this difference that each new tab is created using a raw pointer (new) and we forget to delete them. Qt devs say that the resources are freed when the parent closes.
Conclusion: It's not something good not to free the resources we're done with and wait until the parent is closed.
Probably hours later the parent is closed. Also, most modern OSes do precisely the same duty - freeing all resources gathered by the app when it closes. So that relation is useless, because freeing is delayed by this relation for several hours.

They might say, they can parent the new tab with something other than the main window, so that its resource is freed at the time it closes. OK, to what other item in such a project we can parent them?

Furthermore, we may close merely 10 of those tabs and work on the other 10 in addition to the first tab, until midday!

I suppose, all variants of the scenario are worked out using smart pointers, but the situation is different, causing memory leak, when we leave smart pointers out and make use of the parent-child relation.

Last edited on
Qt had "solutions" pre-dating the C++ standard for smart pointers.

Indeed.


Having a smart pointer does not guarantee problem-free life. GUI framework (like Qt) has to be used the way it is designed to be used. Shoehorning smart pointers to everything leads to pain.


One does not simply "close a tab".
1. User sees a button in tab (or shortcut key) that represents closing a tab. (Somebody did add those.)
2. User activates the button/key. A "close action event" occurs.
3. Something in the program handles the close action.

If you do give the user a way to close a tab, then you have to supply the handler that will implement the close action. It is perfectly logical to write the handler in a way that it does all necessary steps. It is hard to justify that you "forget" to appropriately remove a widget in a short function, whose only purpose is to remove the widget.


A smart pointer manages the memory that it points to. The smart pointer does delete, when the smart pointer object is destroyed. What does destroy the pointer object in your scenario?
Is it an automatic object that goes out of scope? What scope?
Is it dynamically allocated object that is explicitly deleted? By what? By a smart pointer to smart pointer?

No, frek, that is not the silver bullet that you are looking for. Your browser tabs seem to require explicit destruction no matter how you implement them.
causing memory leak, when we leave smart pointers out and make use of the parent-child relation.


It's not a leak, Frek.

Not a leak.

Simply using some memory is not the same as leaking memory.
OK, we delete each tab, freeing its memory allocated as well, using an overridden close virtual event, for example. We could've done it with an independent program (with no parent), couldn't we?

So what is the role of parent-child relation here?
In Qt, assigning a QObject a parent gives the parent ownership of the object. When the parent destructs, it calls delete on all its children.

This model works very well in GUI programming, because in a GUI, it is common to have nested UI elements. There is no point in a combobox continuing to exist if the parent window it is part of no longer exists.

A unique_pointer and the object it points at are in an identical relationship. When the unique_pointer destructs, it calls delete on what it points at.
Last edited on
Thank you, it's right and I knew that, but asked a contrary question.

Did you read my above post? Assume we handle code so nicely that it releases each object's resource when it is closed like the way explained in the above post. Now do you still need our widget to be parented? Or what's/re the advantage(s), (if any) of that parent-child relation in this case?

To me, it only removes the closed child(ren) from its tree hierarchy, and nothing else.
The advanatge is that it makes your code a lot simpler, a lot easier to read and understand, a lot easier to maintain and a lot less prone to bugs.

If you're using Qt, there are also Qt functions that enable a parent to interact with its child in ways other than just memory handling, and if you abandon the parent-child relationship, you presumably commit yourself to also doing all that manually. Many of Qt's built-in widgets use this parent-child relationship to work out on-screen layout and so forth; if you abandoned it, I would expect things to look awful and possibly just not work at all.

It seems that you're asking "if there is no role for the parent-child relationship, is there any role for the parent-child relationship?"
Last edited on
@frek,

I think by this:


Now do you still need our widget to be parented? Or what's/re the advantage(s), (if any) of that parent-child relation in this case?


The operating systems implementing GUI have parent/child relationships in the objects created using a C API (in most that I know). There are, along the way, a range of GUI objects which are acquired, like device contexts, icons, brushes, pens...these belong to the operating system. They are not allocated as memory, they are acquired in a way more analogous to a file handle. What your application receives from such a resource is usually a handle (a numeric identifier, not a memory location).

This is what RAII is aimed at helping to control, but it is not a smart pointer required, it is more abstract representation, something along the lines of the way that iostream will represent a file, when it is opened.

The GUI's relationships (parent/child, or the objects like contexts that may be acquired upon them) must be modeled by a C++ framework in order to assist in controlling them.

It would, therefore, be the RAII implementation in that framework which controls the acquisition and release of those related resources.

The smart pointers would be limited to those C++ objects allocated within the framework.

It is common (perhaps unfortunately) that when using frameworks (not just GUI, but physics engines, game engines, database systems, math libraries) that those frameworks may employ their own version of memory management. As long as it works, there's no reason to reconsider their design. Some may have their own smart pointers for memory, and may well exhibit a "smart pointer like" behavior relative to representative object classes like brush, dc, pen, window (panel), etc.
Topic archived. No new replies allowed.
Pages: 12