PDA

View Full Version : Basic question on new and delete



jcr
18th January 2006, 00:47
Hi,

Quite a basic question concerning dynamic memory allocation.
int main()
{
int* p = new int();
return 0;
}
I am assuming that the above program is harmless to the computer. Is that right? Does C++ guarantee that on program termination, the memory pointed to by P is freed? Is there a good reason why I should still insert an "delete p';"? Is the answer the same for every operating system?
Tanks and congratulations on the new qt forum.
JCR

wysota
18th January 2006, 01:08
I am assuming that the above program is harmless to the computer. Is that right? Does C++ guarantee that on program termination, the memory pointed to by P is freed? Is there a good reason why I should still insert an "delete p';"? Is the answer the same for every operating system?

It is said to be OS dependent. For example on Linux the memory is freed for sure, but on Windows it is said to make a memory leak.

Why should you insert a delete statement? For three reasons. First has already been mentioned -- a memory leak after the process ends. Second one is about elegance. Third is that one day you may want to reuse the code as part of some bigger framework and if you don't notice that missing delete (which is very likely to happen), you'll end up with a memory leaking process.

yop
18th January 2006, 08:25
...you may want to reuse the code as part of some bigger framework and if you don't notice that missing delete (which is very likely to happen), you'll end up with a memory leaking process.Think that you mght have an application that runs for several hours and that the memory is allocated meny times without freeing it, eventually your memory resources will run out and your app will remind you a very popular OS back in '95 ;)

Codepoet
18th January 2006, 14:16
Another good reason for delete is that you may have, at another place, a memory leak. If you use a memory debugger to find these you will get much less warnings this way.

rh
19th January 2006, 10:23
Or simply create all your objects as value types (ala RAII) and just let them die of natural causes when they're out of scope. After all, pointers are SO yesterday :D

yop
19th January 2006, 10:28
After all, pointers are SO yesterday :DI'm sooo with you. If you can avoid them you save yourself a lot of troubles

Codepoet
19th January 2006, 10:28
Or simply create all your objects as value types (ala RAII) and just let them die of natural causes when they're out of scope. After all, pointers are SO yesterday :D
That's a very bad idea: In another thread somebody did that:


for(int i = 0; i < 5; ++i)
{
QThreadDerivedClass t;
t.start();
}

Just after starting the thread the instance will be destructed because it went out of scope. You need pointers to avoid some very ugly code. Maybe use them through something like boost::shared_ptr with automatic reference counting, it's even exception safe.

yop
19th January 2006, 10:45
...because it went out of scope...This was an implementation bug ;) What would you prefer in the following situation?

MyModalDialog modalDlg;
modalDlg.exec()
if(modalDialog.getSomething()==true){
//do something;
}
or

MyModalDialog *modalDlg = new MyModalDialog;
modalDlg->exec()
if(modalDialog->getSomething()==true){
//do something
}
delete modalDlg;
Then after code being added by many others...

MyModalDialog *modalDlg = new MyModalDialog;
modalDlg->exec()
if(modalDialog->getSomething()==true){
//do something
}else{
return; //Ouch
}
// Lot's of code that might also return somewhere
delete modalDlg;

I'm not saying don't use pointers, but why not avoid them whem they are not needed?

Codepoet
19th January 2006, 11:05
@yop: I cited not you but rh ;)
Yes one can (should?) avoid them if possible: Your example perfectly demonstrates it. It gets even worse when you work with exceptions.
I never meant not using instances on the stack, that's most of the time ok but not always.

rh
19th January 2006, 11:30
The only real restriction to RAII-style initialized variables that i've encountered is, to state the obvious, that its type must be known at compile-time. Anything with runtime attributes (such as factory classes, etc.) still require pointers.

My biggest qualm on using pointers? That damn "->" operator! C++ is *supposed* to be a language of type reduction, yet the arrow operator is 3x the keystrokes (don't forget the shift) as other dot-notated languages.

If this makes me shallow (also i like ladies with big boobies), then so be it but in my opinion, RAII initialized variables are not only easier on the carpal tunnel, but are inherently safer (like GC without the overhead) and should be used whenever possible.

I realize this is drifting slightly from the original post. If everyone is happy with me having the last word i'm good with that :)

GreyGeek
19th January 2006, 16:12
Hi,

Quite a basic question concerning dynamic memory allocation.
int main()
{
int* p = new int();
return 0;
}
I am assuming that the above program is harmless to the computer. Is that right? Does C++ guarantee that on program termination, the memory pointed to by P is freed? Is there a good reason why I should still insert an "delete p';"? Is the answer the same for every operating system?
Tanks and congratulations on the new qt forum.
JCR
As I understand it C++ does NOT guarantee that the memory is freed. That is your job. And, I read somewhere that delete[] is the prefered form of that command, even if your pointer isn't an array.

That's one of the beneies of using QT. If your class objects inherit from QObject or QWidget then QT's automatic garbage collection takes over, much as Java does. If your class objects don't inherit from those two QT objects then it's YOUR responsibility to make sure they get deleted before they lose scope.

Codepoet
19th January 2006, 17:50
It is an error to use delete[] on a pointer allocated with new and vice versa. Everything else may work on some implementations on some not...

Qt garbage collection works in principle like you described: But it suffices not to derive from QObject. QObject derived classes are guaranteed to be deleted when their parent is deleted. So when they have none it is still your responsibility to do it.


@rh: Maybe switch to Dvorak? Helps not with "->" but everything else is great ;) And I type much more other letters then these two... Maybe try something with autocompletion?
Ah - you should use macros to avoid the curly braces - that would be wrist friendly :rolleyes:

And RAII-style should be used for pointers too - that's one of it's main applications when you program exception safe.

Chicken Blood Machine
29th January 2006, 22:59
As I understand it C++ does NOT guarantee that the memory is freed. That is your job. And, I read somewhere that delete[] is the prefered form of that command, even if your pointer isn't an array.

That's one of the beneies of using QT. If your class objects inherit from QObject or QWidget then QT's automatic garbage collection takes over, much as Java does. If your class objects don't inherit from those two QT objects then it's YOUR responsibility to make sure they get deleted before they lose scope.


This is incorrect, the memory is always released back to the operating system at program termination. However, this is still technically a memory leak and it is good practice to use 'delete p' on your pointer.

delete[] p should only used on pointers that were assigned to arrays created with new type[], e.g:



int* p = new int; // delete with 'delete p;'
int* a = new int[5]; // delete with 'delete[] a;'

GreyGeek
30th January 2006, 18:00
This is incorrect, the memory is always released back to the operating system at program termination. However, this is still technically a memory leak and it is good practice to use 'delete p' on your pointer.

I thought that the definition of a memory leak was a situation in which the memory was NOT returned to the OS at program termination. Successive leaks can "eat up" the heap until there is none left. How could memory be returned back to the OS and that memory still be a 'leak'? If the OS has it can't it re-use it?



delete[] p should only used on pointers that were assigned to arrays created with new type[], e.g:



int* p = new int; // delete with 'delete p;'
int* a = new int[5]; // delete with 'delete[] a;'

I've read that too. But, IIRC, Tom Swan's book said that using "delete[] p" will 'guarantee' that p is deleted regardless of if it was array or not. I haven't tried in my app because my app doesn't use pointers, but the code example in Tom Swan's book didn't bomb.
???

What would happen if one used "delete[]" on a pointer that wasn't an array?

Chicken Blood Machine
30th January 2006, 18:38
I thought that the definition of a memory leak was a situation in which the memory was NOT returned to the OS at program termination. Successive leaks can "eat up" the heap until there is none left. How could memory be returned back to the OS and that memory still be a 'leak'? If the OS has it can't it re-use it?


Consider a program that continuously calls 'new' in a loop without calling delete. This program is 'leaking' memory for every iteration of the loop and will eventually exhaust the physical memory in the system. The fact that this memory will be released when the program terminates is irrelevant here, because the program leaks more and more memory as it runs.

Conversely, it is usually considered 'safe' to leak memory for variables that exist for the lifetime of the program, since that memory use is a constant and does not grow with respect to time as the program runs.



I've read that too. But, IIRC, Tom Swan's book said that using "delete[] p" will 'guarantee' that p is deleted regardless of if it was array or not. I haven't tried in my app because my app doesn't use pointers, but the code example in Tom Swan's book didn't bomb.
???

What would happen if one used "delete[]" on a pointer that wasn't an array?

It would probably fine, but Stroustroup may not like it! Also, to a casual reader of the code, he may mistakenly think that the variable pointed to an array of memory. Using the correct variant of delete, makes the nature of the original allocation clearer.

GreyGeek
30th January 2006, 23:06
Consider a program that continuously calls 'new' in a loop without calling delete. This program is 'leaking' memory for every iteration of the loop and will eventually exhaust the physical memory in the system. The fact that this memory will be released when the program terminates is irrelevant here, because the program leaks more and more memory as it runs.

Ok, I see where you are coming from. While the program is running it is constantly leaking memory and will run out, probably crashing the program, if nothing else.

But, after the program quites aren't the leaks still leaks... i.e., hasn't the memory been lost to the system until a reboot?

And, doesn't QOBJECT take care of heap space that wasn't returned to memory when a) the object based on QOBJECT loses scope or b) the program quites? (Doesn't a=b?) Otherwise, if quiting the program recovers all leaked memory then the only purpose for QOBJECT is to prevent memory leaks (do garbage collection?) WHILE the program is running. Yet, I've seen several examples of programs that show a heap's size being reduced each time an app is run and then quites, so the the memory isn't returning to the heap (OS?) when the program quits.
:confused:

Chicken Blood Machine
31st January 2006, 00:00
Ok, I see where you are coming from. While the program is running it is constantly leaking memory and will run out, probably crashing the program, if nothing else.

But, after the program quites aren't the leaks still leaks... i.e., hasn't the memory been lost to the system until a reboot?


I don't believe this ever to be the case, but maybe there is a (faulty) OS that proves me wrong!



And, doesn't QOBJECT take care of heap space that wasn't returned to memory when a) the object based on QOBJECT loses scope or b) the program quites? (Doesn't a=b?) Otherwise, if quiting the program recovers all leaked memory then the only purpose for QOBJECT is to prevent memory leaks (do garbage collection?) WHILE the program is running. Yet, I've seen several examples of programs that show a heap's size being reduced each time an app is run and then quites, so the the memory isn't returning to the heap (OS?) when the program quits.
:confused:

QObject is not a garbage collector and does nothing really spectacular. All it does is delete all of it's children when it is deleted nothing more (the children will recursively delete their children, etc). This is a simple parent-child pattern and is present in many GUI toolkits, even X-Motif! Don't forget, you still have to delete the topmost parent QObject for this to work. (A toplevel QObject always has a null parent)

When a variable goes out of scope in C++, it is destroyed. Always. This is a guarantee of the C++ runtime and nothing else. The use of Qt/QObject is irelevant. This applies to all types of variables even pointers. However, when a pointer goes out of scope, the object pointed to is not destroyed. You have to take care of this with delete. There are alternative methods you can use to avoid this like std::auto_ptr and boost smart pointers, but at the fundamental level, you must deallocate the memory yourself.

Where QObject really helps out is when you create a GUI. A toplevel window, say derived from QMainWindow, may contain a myriad of other subwidgets within itself (Consider a complex gui that you have created in Designer). When you intsantiate your main window widget, you may do it like this:



MyMainWindow* mw = new MyMainWindow(0);// note null parent


Within the MyMainWindow constructor, there will be code that creates and arranges many child widgets of the main window.


When you delete the mainwindow, you would do so like this


delete mw;


You don't worry about deleting all the pushbuttons, listboxes, labels etc that are within your main window. Why? because QObject takes care of it with its parent-child model.

To finish, consider the following example:


MyMainWindow::doSomethingSlot()
{
// Create a dialog and show it
MyDialog* dlg = new MyDialog(this); // parented to this mainwindow
...
...
dlg->exec();// display the dialog
}


This code leaks memory - badly. Why? You may ask. "I have parented my dialog to my main window, shouldn't it be cleaned up when the main window is destroyed?". Yes, but when will the window be destroyed? Probably somewhere just before your app terminates. How many times may doSomethingSlot() be called before this happens? Every time it is called an instance of MyDialog is created that floats off into the ether after it is no longer required.

The preferred approach here would be to delete the pointer at the end of the function or to create the dialog on the stack instead of calling 'new'.

[Incidentally, QObject::deleteLater() is often a better alternative to a straightforward 'delete' on a QObject, but that's another story!]

GreyGeek
31st January 2006, 04:59
...snip...
Where QObject really helps out is when you create a GUI. A toplevel window, say derived from QMainWindow, may contain a myriad of other subwidgets within itself (Consider a complex gui that you have created in Designer). When you intsantiate your main window widget, you may do it like this:



MyMainWindow* mw = new MyMainWindow(0);// note null parent


Within the MyMainWindow constructor, there will be code that creates and arranges many child widgets of the main window.


When you delete the mainwindow, you would do so like this


delete mw;


You don't worry about deleting all the pushbuttons, listboxes, labels etc that are within your main window. Why? because QObject takes care of it with its parent-child model.

Well, here is the main function, from my main.cpp, from my Homestead application:


int main( int argc, char * argv[] ) {
QString strRejected = "";
QApplication app(argc, argv);
app.setQuitOnLastWindowClosed(false);
dlgLogin dlg;
if( dlg.exec() == QDialog::Accepted ){
QSqlDatabase hapdb = QSqlDatabase::addDatabase(DBDRIVER);
hapdb.setHostName(DBHOST);
hapdb.setDatabaseName(DBNAME);
hapdb.setUserName(dlg.dui.leUserName->text());
hapdb.setPassword(dlg.dui.leUserPassword->text());
if ( hapdb.open() ) {
homestead ht;
ht.RevID = dlg.dui.leUserName->text();
ht.show();
app.setQuitOnLastWindowClosed(true);
return app.exec();
} else {
strRejected = QString("The Login was rejected because: %1").arg(hapdb.lastError().text()).toLatin1();
QMessageBox::information(0,"Login Rejected!",strRejected,
QMessageBox::Ok,QMessageBox::NoButton,QMessageBox: :NoButton);
return 1;
}
} else {
strRejected = QString("User Canceled the login!").toLatin1();
QMessageBox::information(0,"Login Rejected!",strRejected,
QMessageBox::Ok,QMessageBox::NoButton,QMessageBox: :NoButton);
return 2;
}
}

As I understand your comments, since "dlg" is called only once, and that call is in this function, its memory will be recovered when main goes out of scope (i.e., the app closes). And, hapdb is also instantiated only once so its memory, too, will be reclaimed when the app closes. The ht object, where Homestead really operates, is also instantiated only once and like the others, the memory it uses is returned to the OS when the app closes. So, I don't need as the last three lines of main():


delete ht;
delete hapdb;
delete dlg;

because none of these objects leak memory, even though dlg has a parent:


class dlgLogin : public QDialog
{
Q_OBJECT
public:
Ui::dlgLoginUi dui;
dlgLogin()
{
dui.setupUi(this);
dui.leUserName->setText("your revid");
dui.leUserPassword->setText("");
dui.leUserName->setFocus();
dui.leUserName->selectAll();
}
};

but homestead does not...


class homestead : public QMainWindow
{
Q_OBJECT
public:
homestead(QWidget *parent = 0);
...


Right?

Chicken Blood Machine
31st January 2006, 06:02
Well, here is the main function, from my main.cpp, from my Homestead application:


int main( int argc, char * argv[] ) {
QString strRejected = "";
QApplication app(argc, argv);
app.setQuitOnLastWindowClosed(false);
dlgLogin dlg;
if( dlg.exec() == QDialog::Accepted ){
QSqlDatabase hapdb = QSqlDatabase::addDatabase(DBDRIVER);
hapdb.setHostName(DBHOST);
hapdb.setDatabaseName(DBNAME);
hapdb.setUserName(dlg.dui.leUserName->text());
hapdb.setPassword(dlg.dui.leUserPassword->text());
if ( hapdb.open() ) {
homestead ht;
ht.RevID = dlg.dui.leUserName->text();
ht.show();
app.setQuitOnLastWindowClosed(true);
return app.exec();
} else {
strRejected = QString("The Login was rejected because: %1").arg(hapdb.lastError().text()).toLatin1();
QMessageBox::information(0,"Login Rejected!",strRejected,
QMessageBox::Ok,QMessageBox::NoButton,QMessageBox: :NoButton);
return 1;
}
} else {
strRejected = QString("User Canceled the login!").toLatin1();
QMessageBox::information(0,"Login Rejected!",strRejected,
QMessageBox::Ok,QMessageBox::NoButton,QMessageBox: :NoButton);
return 2;
}
}

As I understand your comments, since "dlg" is called only once, and that call is in this function, its memory will be recovered when main goes out of scope (i.e., the app closes). And, hapdb is also instantiated only once so its memory, too, will be reclaimed when the app closes. The ht object, where Homestead really operates, is also instantiated only once and like the others, the memory it uses is returned to the OS when the app closes. So, I don't need as the last three lines of main():


delete ht;
delete hapdb;
delete dlg;



That would not even compile. None of the variables you mentioned are pointer variables, so how could you ever call delete on them? Your code (above) as listed will not leak any memory, because all objects are created on the stack.



because none of these objects leak memory, even though dlg has a parent:


class dlgLogin : public QDialog
{
Q_OBJECT
public:
Ui::dlgLoginUi dui;
dlgLogin()
{
dui.setupUi(this);
dui.leUserName->setText("your revid");
dui.leUserPassword->setText("");
dui.leUserName->setFocus();
dui.leUserName->selectAll();
}
};



Dialog does NOT have a parent. Look how you instantiated it



dlgLogin dlg; // <- No parent


It's constructor does not event have a QWidget* 'parent' parameter, so there is no way to create a dlgLogin object with a parent (even if you wanted to).

What makes you think that it has a parent?



but homestead does not...


class homestead : public QMainWindow
{
Q_OBJECT
public:
homestead(QWidget *parent = 0);
...


Right?

Correct (but not for the reason that you have stated). Your homestead object does not have a parent, because you declared it like this:


homestead ht;


If you wanted it to have a parent, you would have declared it like this:


...
homestead ht(parent); // Parent is some QWidget*, declared further up


In both cases, the fact theat you declared your widgets with no parent is fine, because you are ensuring their destruction by declaring them on the stack (not as pointers allocated with 'new') and therefore, they are destroyed when they run out of scope.

GreyGeek
1st February 2006, 20:46
That would not even compile. None of the variables you mentioned are pointer variables, so how could you ever call delete on them? Your code (above) as listed will not leak any memory, because all objects are created on the stack.

That I knew, I was just supposing that if they were created by "new" would it matter if they were deleted using the delete operator because they were going out of scope anyway if, as you say, the OS will always get the memory back.




Dialog does NOT have a parent. Look how you instantiated it



dlgLogin dlg; // <- No parent


It's constructor does not event have a QWidget* 'parent' parameter, so there is no way to create a dlgLogin object with a parent (even if you wanted to).

What makes you think that it has a parent?
Because it inherited from QDialog?
class dlgLogin : public QDialog

An ancestor isn't a parent?
(I told you I was new to C++) :)



Correct (but not for the reason that you have stated). Your homestead object does not have a parent, because you declared it like this:


homestead ht;


If you wanted it to have a parent, you would have declared it like this:


...
homestead ht(parent); // Parent is some QWidget*, declared further up


In both cases, the fact theat you declared your widgets with no parent is fine, because you are ensuring their destruction by declaring them on the stack (not as pointers allocated with 'new') and therefore, they are destroyed when they run out of scope.

So, using "new" as shown below means that "ui.gridMultiProp" is a parent to *model ??


QSqlQueryModel *model = new QSqlQueryModel(ui.gridMultiProp);

Pardon the dumb questions but you'll dealing with someone who has read perhaps too much and it's all jumbled up inside?
It's amazing that I can, using QT, write the app I did and that it works. :D

Chicken Blood Machine
1st February 2006, 23:50
That I knew, I was just supposing that if they were created by "new" would it matter if they were deleted using the delete operator because they were going out of scope anyway if, as you say, the OS will always get the memory back.

Ok, then no, it wouldn't matter. As a matter of good practice, I would delete them anyway though.



Because it inherited from QDialog?
class dlgLogin : public QDialog

An ancestor isn't a parent?
(I told you I was new to C++) :)

No, QDialog is its baseclass, not its parent. The parent is the object you pass as the QWidget* parameter (which can be NULL). 'Baseclass', 'superclass' or 'inherited class' are names for the same C++ OO constructs. 'Parent' (in this context) is a Qt construct and refers to ownership, not inheritance. Reading the comprehensive documentation of QObject will explain it more.



So, using "new" as shown below means that "ui.gridMultiProp" is a parent to *model ??


QSqlQueryModel *model = new QSqlQueryModel(ui.gridMultiProp);


That's correct.



Pardon the dumb questions but you'll dealing with someone who has read perhaps too much and it's all jumbled up inside?
It's amazing that I can, using QT, write the app I did and that it works. :D

It is amazing. Did you check your prog for memory leaks :)
Actually, it's a very bad idea to use Qt to learn C++ (not suggesting that you did it this way). It is much better to learn C++ and get confident with it (warts and all), then start using Qt to see how much easier it makes your life! The QObject parent-child model along with the references counted non-QObjects really help cut down on the amount of memory management that you have to worry about (but you still must be wary).

KjellKod
2nd February 2006, 09:17
Once the program has terminated. The OS (Linux and Windows) will be able to use the memory again. Definition of memory leak is during the lifetime of the program.

However, the OS might not be so nice for awhile if the memory leaking program took up ALL memory resources until it finally crashed. But the first example is a safe example. He makesnew object... (usually doing other stuff too ;-) and then the application quits, and the memory - when it is needed. Will be re-used by the OS.

Another issue is memory fragmentation, which can be a bigger problem on Windows I fear.

ct
14th February 2006, 07:38
Welll I have a very basic query on this matter.. What happens if the application is run continuously where it will have several instances of new.
Lets say at the end of the program it says:
Do you want to quit or continue ?

If the user wants to continue then the main application has not been quit.. so all the instances of "new" that were originally there will again be made..as the program will again run from the beginning .
In such case does QT takes care of freeing the memory..or we have to manually free up all the memory taken by the object ..

jacek
14th February 2006, 12:05
In such case does QT takes care of freeing the memory..or we have to manually free up all the memory taken by the object ..
Qt will delete only objects derived from QObject that have a parent and only if their parent gets deleted.

ct
14th February 2006, 16:06
so say in case of something like messenger, where one logs out all the objects needs to be manuallly freed so that new instances could be formed for the new sign in procedure ..

jacek
14th February 2006, 16:09
so say in case of something like messenger, where one logs out all the objects needs to be manuallly freed so that new instances could be formed for the new sign in procedure ..
If they aren't QObjects or they have no parents, yes.