1

I've been studying C++ for my Thesis with Bjarne Stroustrup's book [ C++ 11 ]. Even so, I'm still not getting somethings about handling memory leak in C++. He says a lot in the book to avoid the use of new, delete and also custom destructors.

I would like to say I'm using QT to build my UI, now please consider this example for my first three question:

    class KHUB : public QMainWindow
{
    Q_OBJECT

public:

    KHUB(QWidget *parent = 0)
    {
        createGroupScreen();
    };

    ~KHUB();

private:

        QWidget *groupScreen;
        void createGroupScreen()
        {
            groupScreen = new QWidget();
        };
}

This is resumes my app. I have a constructor named KHUB which creates a dialog (QWidget) giving some options to put name, category and so on, to create a new group.

  1. Since I'm supposed to avoid naked new and delete, is there a different way (such as using unique_ptr, not sure if it's an applicable concept here) or not so error prone to create this QWidget and still have the object reference to manipulate it outside the my createGroupScreen member function?

  2. if I create this object inside the member function, without a global pointer and also not using naked new, this object will remain in the memory as long as it's parent is alive or in the end of the member function it will be deleted?

  3. if it remains alive with its parent, how can I acquire the object reference outside the member function so I can call ~QWidget()?

My fourth question regards to this same object destruction.

  1. If I destroy groupScreen by calling groupScreen->~QWidget() this will only destroy my QWidget object and my pointer will remain there as a memory leak waiting for me to delete groupScreen?

Consider this another piece of code for my fifth, sixth and last question:

        class KHUB : public QMainWindow
{
    Q_OBJECT

public:

    KHUB(QWidget *parent = 0)

    ~KHUB()
    {
        delete groupScreen;
        delete buttonOne;
        delete buttonTwo;
        delete buttonThree;
    };

private:

        QWidget *groupScreen;

        QPushButton *buttonOne, *buttonTwo, *buttonThree;

        /* Components Setup */
        void btSetup(QPushButton** button, const QString name, int posX, int posY, int width, int height);
}

I'm trying to make some code reuse with buttons with a function to set the button name, position and size, thus the code won't become so big by typing the same parameters repeatedly to each one of them - but I'm also worried with the program performance.

  1. When I call my KHUB constructor, that doesn't mean all global pointers that I have in my .h file are being allocated right? That only happens when they are initialized, correct?

  2. If I really need to create my custom destructor, I should delete in it every global pointer declared in my .h file? I'm wondering if that wouldn't be risk in case I didn't pass through the initialization of one of those pointers.

  3. Is there a way to loop the pointers acquirement and delete? i.e. for(auto p : globalPtrs) delete p;

I tried to find some questions regarding this subject here at stack but none was really enlightening to me:

  1. C++ destructor memory leak
  2. Avoiding memory leak
  3. Avoiding memory leaks
Community
  • 1
  • 1
Victor Oliveira
  • 3,293
  • 7
  • 47
  • 77
  • 1
    My understanding of the memory leaks (I am sure other people will correct me or have better information) is that whatever object you are working with pointer class ext.. They exist in memory or ram has long has it is within scope. Memory leaks come from unnecessary things in scope all taking up space from memory.If you can’t use delete just maybe you can set what you are working with to NULL. The OS you are using magically will handle memory allocation for new objects. Smart Pointers are a thing btw this is a great atrial about them http://www.umich.edu/~eecs381/handouts/C++11_smart_ptrs.pdf – T.Malo Mar 11 '15 at 15:04
  • You should be using `std::make_shared` and `std::make_unique` whenever possible, instead of passing the result of `new` to the smart pointer constructor. That's what's *also* meant by not using `new` directly. – Kuba hasn't forgotten Monica Mar 11 '15 at 15:51
  • Finally, it's rather rare that you'd call a destructor directly and explicitly. I've just looked through a 50k LOC project I'm currently working on, and there isn't a single explicit destructor call anywhere. You need to have a very good reason to do so, pretty much. If you're not writing manual resource management library code, you probably shouldn't be calling destructors explicitly. – Kuba hasn't forgotten Monica Mar 11 '15 at 15:54
  • You're also forgetting that a `QObject` is a smart pointer collection (really!). A `QObject` is like `std::vector>`. A `QObject` is a smart pointer with unique ownership of its children. It's often counterproductive to apply additional layers of memory management to owned `QObject`s. If they have a parent, the parent worries about them. – Kuba hasn't forgotten Monica Mar 11 '15 at 15:57
  • 1
    Finally, it doesn't make much sense to store unique pointers to child widgets in the parent widgets. The children can be simple direct members, not pointer members. – Kuba hasn't forgotten Monica Mar 11 '15 at 15:58

1 Answers1

2

Probably you should start by reading the C++ FAQ on memory management

Since I'm supposed to avoid naked new and delete, is there a different way (such as using unique_ptr, not sure if it's an applicable concept here) or not so error prone to create this QWidget and still have the object reference to manipulate it outside the my createGroupScreen member function?

Yes, if modern C++, you are supposed to use std::shared_ptr or std::unique_ptr or std::weak_ptr. All of them take care of the destruction of the memory they refer to. Each of them has different characteristics regarding ownership, sharing, etc.

I'd try to use them, as they simplify memory management. If not possible (e.g. your compiler is not up to C++11 and are not using boost... there might be many reasons), you can use new/delete... just be extra careful.

if I create this object inside the member function, without a global pointer and also not using naked new, this object will remain in the memory as long as it's parent is alive or in the end of the member function it will be deleted?

Not sure what you mean. if you're creating a variable, method/function local, object attribute... etc.. The variable will be destroyed when the scope it is defined in goes away.

Say you have:

void myfunc() {
   int a=0;
}

when you enter the scope the memory for the integer a is created and when you go out of the scope the memory for the integer a is destroyed. In this case it will be memory on the stack (vs. memory on the heap)

If you have an attribute in an class, when the object is created, the attribute will be created (constructor). When the object is destroyed, the attribute will be destroyed (destructor).

When you are allocating with new, memory is allocated from the heap. If you store a reference to that memory in a (plain) pointer variable, when the pointer variable is destroyed, the memory referenced by the pointer is not destroyed (and you have a leak).

Same thing can be said when you have memory referenced by a pointer and you assign a different memory reference to that pointer. If the memory is not referenced elsewhere, it is lost to your program.

if it remains alive with its parent, how can I acquire the object reference outside the member function so I can call ~QWidget()?

if you allocated with new, then you must either destroy it when going out of scope or save the memory reference to a pointer variable in some other scope from where you can delete it what the time comes.

See the C++ FAQ:Why isn’t the destructor called at the end of scope?

Something you might want to read about is RAII as the smart pointer I listed in the first question use this idiom.

If I destroy groupScreen by calling groupScreen->~QWidget() this will only destroy my QWidget object and my pointer will remain there as a memory leak waiting for me to delete groupScreen?

See the C++ FAQ:What are the two steps that happen when I say delete p?

Calling delete groupScreen will cause the ~QWidget() to be executed and the destructors of all the attributes (non-pointer/reference) and the destructor of the parent classes (if any) and the memory for the object deallocated.

When you are dealing with a hierarchy of classes, it is important to consider if the object might be deleted through a pointer to the parent class(es). If that's the case, the destructor method must be declared virtual, so that actual object class method is executed (instead of executing the destructor of the class pointed to by the pointer) (which is yet another form of leak).

When I call my KHUB constructor, that doesn't mean all global pointers that I have in my .h file are being allocated right? That only happens when they are initialized, correct?

When you call the constructor, before executing your custom constuctor, the attributes will be allocated. But a pointer will not be allocated memory an assigned to it, just memory for the pointer itself (and it is important that you take care of initializing it to some sane value, e.g. null_ptr)

variables you declare outside of a class or static attributes of a class, should not be initialized in a *.h, as they will cause symbols to appear multiple times (as the header is included in different compilation units)

Initialize them in the *.cpp. However be careful as it might be a cause of problems (see C++ FAQ)

If I really need to create my custom destructor, I should delete in it every global pointer declared in my .h file? I'm wondering if that wouldn't be risk in case I didn't pass through the initialization of one of those pointers.

You should create a custom destructor if

  • You want to do anything on object destruction
  • If your object contains dynamic memory (naked) pointers that it owns (i.e. that will not be taken care of by someone else)

Is there a way to loop the pointers acquirement and delete? i.e. for(auto p : globalPtrs) delete p;

not entirely sure what you mean by globalPtrs... if it is some magical variable that contains all the pointers in an object, there's not such a thing.

You must take care of the deletion of every pointer (you owned)... that's why the smart pointers are much less error-prone, as they will do it automatically.


Perhaps an example will help:

#include <iostream>

class B {
public:
  B() {
    std::cout << "B()" << std::endl;
  }

  ~B() {
    std::cout << "~B()" << std::endl;    
  }
};

class A {
public:
  A() {
    std::cout << "A()" << std::endl;
  }

  ~A() {
    std::cout << "~A()" << std::endl;    
  }
  B b;
};

int main() {
  std::cout << "A as variable" << std::endl;
  A a;

  std::cout << "A as pointer" << std::endl;
  A *a_ptr=0;

  std::cout << "running new" << std::endl;
  a_ptr=new A();

  std::cout << "running delete" << std::endl;
  delete a_ptr;    

}

This produces the following output (with some annotations)

A as variable     // We are declaring a stack variable of type A
B()               // since A contains a B attribute object it creates it 
A()               // ... and runs the constructor
A as pointer      // We are declaring a stack variable pointer to A
                  // ... nothing happens
running new       // but when we run new, we get
B()               // the creation of the attribute (and its constructor)
A()               // the execution of the constructor
running delete    // now we call delete
~A()              // that calls A's destructor
~B()              // and then proceeds to destroy the attributes.
~A()              // these are the destructor for the first variable
~B()              // which is now going out of scope

let's try something different. Same classes definition. Our main is now:

int main() { 
  std::cout << "A as pointer" << std::endl;
  A *a_ptr=0;

  std::cout << "running new" << std::endl;
  a_ptr=new A();

}

We get

A as pointer
running new
B()
A()

No destructor, we've leaked the A object.

jsantander
  • 4,972
  • 16
  • 27
  • "Calling delete groupScreen will cause the ~QWidget() to be executed and the destructors of all the attributes (non-pointer/reference) and the destructor of the parent classes (if any) and the memory for the object deallocated." Are you sure about this? I thought this would make me lose the reference to my QWidget and cause memory leak, I thought I should destroy the object first and then delete the pointer. - I appreciate your help, but I will wait to see if someone else answers me, some of your answers doesn't really clarify my doubts but it helped – Victor Oliveira Mar 11 '15 at 14:59
  • 1
    @VictorOliveira. I've added some sample code. You can use the same technique to test your assumptions: add traces to see what is executed when. – jsantander Mar 11 '15 at 15:24
  • I checked your delete information with vld.h (memory leak manager) and you are right – Victor Oliveira Mar 11 '15 at 15:41
  • I must ask, if I'm deleting my pointer that means its allocated space will no longer exist in the memory or I'm just freeing any reference that he is pointing to? – Victor Oliveira Mar 11 '15 at 15:50
  • 1
    This answer is only half an answer. It's accurate, but it completely misses that it's `QObject`s that are talked about. – Kuba hasn't forgotten Monica Mar 11 '15 at 15:59