Qt-interest Archive, August 2007
Stack vs. Heap
Pages: Prev | 1 | 2 | Next
Message 1 in thread
Hi!
I understand the parent-child mechanism. But allocating and deallocating
heap memory on the fly is expensive.
* What is an argument against objects on the stack? (The limited stack
size is not the question here.)
* Is there any risk by doing my own memory management by omitting
parent's address within child's constructor and deleting objects
manually (within the destructor)?
Regards
Lars
--
[ signature omitted ]
Message 2 in thread
On 10.08.07 23:24:18, Lars Knoesel wrote:
> I understand the parent-child mechanism. But allocating and deallocating heap
> memory on the fly is expensive.
>
> * What is an argument against objects on the stack? (The limited stack size is
> not the question here.)
I guess you mean QObjects (as the next question seems to imply the
automatic deletion of QObject childs). Given that the question is more:
What do you want to do with that object? An object that you create on
the stack can only live until the end of the current block of execution
and as you can't assign QObject instances directly to one another (no
copy-constructor and assignment operator) its not directly possible to
assign this object to a variable from the outside block. Maybe its
possible via references (sorry too late here to think about that fully).
> * Is there any risk by doing my own memory management by omitting parent's
> address within child's constructor and deleting objects manually (within the
> destructor)?
Only the usual risk of creating memory leaks because you forget to
delete one of the objects. However explicit deleting is (AFAIK) only
useful with objects created via new which are created on the heap, so
you don't use that anyway. And member variables that are derived from
QObject don't make much sense because of the missing assignment and copy
stuff.
BTW: Do you have some links that explain how/why allocating on the heap
is more expensive than on the stack? (I'd be interested seriously as I
didn't delve that much into these things myself yet).
Andreas
--
[ signature omitted ]
Message 3 in thread
2007/8/11, Andreas Pakulat <apaku@xxxxxx>:
> On 10.08.07 23:24:18, Lars Knoesel wrote:
> BTW: Do you have some links that explain how/why allocating on the heap
> is more expensive than on the stack? (I'd be interested seriously as I
> didn't delve that much into these things myself yet).
That's very simple to explain: Allocating on the stack costs *nothing* but
incrementing the stack-pointer, while allocating on the heap costs
looking up for a
suitable place in the fragmented RAM, possibly rearranging and
remapping previously
allocated memory pages, etc.
Lars is right, IMHO, that 90% of the "new"s used in Qt are unneccessary.
For example, the child-widgets of a dialog usually (virtually *always*) have
the same lifetime as the parent widget, so it makes perfectly sense to just
have them as normal (i.e. not pointer-) members in the class, instead of having
a pointer as the member and calling new QBla(this) in the ctor, since
it's basically
*the same*, the object will have exactly the same lifetime.
The only true advantage kicks in when reparenting widgets, but I rarely do that,
and a smartpointer-solution would work in that case, too.
Kind regards,
Daniel Albuschat
--
[ signature omitted ]
Message 4 in thread
I don't agree with your assessment.
QT is designed to build truly component software. The management of
memory and connections is well done so that I don't have to be
concerned with walking a window list and deciding what to delete or
disconnect. When a parent dies, it's children die. What if the
child is a stack object? Well you could argue for a flag in QObject
that tells QT not to delete the object, but then you open a can of
worms. On desktop computers today, heap allocation is relatively
quick as compared to the user experience. On QTopia, I imagine that
extra work and care may be required to enhance speed. I.E. On the
Pocket PC platform, I wrote a smaller XML parser as opposed to using
MSHTML. It was 70% faster and made a huge difference in the user
experience. I put forward that this is an exception and not a rule.
What I have just written is just one short argument against what you
propose. There are others.
Regards,
Michael
On Aug 10, 2007, at 4:39 PM, Daniel Albuschat wrote:
> 2007/8/11, Andreas Pakulat <apaku@xxxxxx>:
>> On 10.08.07 23:24:18, Lars Knoesel wrote:
>> BTW: Do you have some links that explain how/why allocating on the
>> heap
>> is more expensive than on the stack? (I'd be interested seriously
>> as I
>> didn't delve that much into these things myself yet).
>
> That's very simple to explain: Allocating on the stack costs
> *nothing* but
> incrementing the stack-pointer, while allocating on the heap costs
> looking up for a
> suitable place in the fragmented RAM, possibly rearranging and
> remapping previously
> allocated memory pages, etc.
>
> Lars is right, IMHO, that 90% of the "new"s used in Qt are
> unneccessary.
> For example, the child-widgets of a dialog usually (virtually
> *always*) have
> the same lifetime as the parent widget, so it makes perfectly sense
> to just
> have them as normal (i.e. not pointer-) members in the class,
> instead of having
> a pointer as the member and calling new QBla(this) in the ctor, since
> it's basically
> *the same*, the object will have exactly the same lifetime.
>
> The only true advantage kicks in when reparenting widgets, but I
> rarely do that,
> and a smartpointer-solution would work in that case, too.
>
> Kind regards,
> Daniel Albuschat
> --
> eat(this); // delicious suicide
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx
> with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
--
[ signature omitted ]
Message 5 in thread
2007/8/11, Michael Simpson <michaelsimpson@xxxxxxx>:
> I don't agree with your assessment.
>
> QT is designed to build truly component software. The management of
> memory and connections is well done so that I don't have to be
> concerned with walking a window list and deciding what to delete or
> disconnect. When a parent dies, it's children die. What if the
> child is a stack object?
Then it dies BEFORE the parent-object, and the parent-object will
not try to delete it.
Those both paradigms can happily live next to each other -- it's just
that Qt docs and Qt examples, etc. seem to emphasize on heap-allocation
in situations where it absolutely is not needed (nor desireable).
> Well you could argue for a flag in QObject
> that tells QT not to delete the object, but then you open a can of
> worms.
Like I just described, such a flag is not needed, because there are
no lifetime-issues with static vs. dynamic allocation.
> On desktop computers today, heap allocation is relatively
> quick as compared to the user experience.
Erm, well, this a vague statement. I am currently programming a list that
is meant to incrementally display like 500.000 items fetched from a
sql-database,
growing asynchronously. Here memory-allocation (especially of small objects like
models) is the main-issue (and, of course, it can't be done on the
stack, at least
in C++).
Bye,
Daniel Albuschat
--
[ signature omitted ]
Message 6 in thread
On 8/11/07, Daniel Albuschat <d.albuschat@xxxxxxxxx> wrote:
>
> 2007/8/11, Michael Simpson <michaelsimpson@xxxxxxx>:
> > I don't agree with your assessment.
> >
> > QT is designed to build truly component software. The management of
> > memory and connections is well done so that I don't have to be
> > concerned with walking a window list and deciding what to delete or
> > disconnect. When a parent dies, it's children die. What if the
> > child is a stack object?
>
> Then it dies BEFORE the parent-object, and the parent-object will
> not try to delete it.
Except when the parent is deleted before the end of the current scope.
Example:
void foo()
{
QObject* heapObject = new MyObjectClass;
MyObjectClass stackObject(heapObject);
delete heapObject; // deletes its children, including stackObject
} // implicit call to stackObject's destructor, but the object has already
been destructed
This example is obviously contrived, but it shows why there could be a
danger. If you want to use a QObject on the stack, it would be best to be
sure that its parent is on the stack (assuming you make the same assurance
for the parent's parent, etc) or don't assign a parent. I would be curious
to know how much faster QObject creation is on the stack vs. the heap.
Remember that these aren't just ints or something, there's a constructor
call that is made no matter what, and my understanding is that QObjects
aren't cheap (which is why some of the smaller classes in Qt do not derive
from QObject).
Tom
Message 7 in thread
Tom Panning wrote:
> Remember that these aren't just ints or something, there's a constructor
> call that is made no matter what, and my understanding is that QObjects
> aren't cheap (which is why some of the smaller classes in Qt do not derive
> from QObject).
>
My experience is that the more peers a QObject has, the longer it takes
to instantiate it, where "peer" is defined as other QObject-derived
instances that have the same parent QObject. The last time I ran the
test was Qt 3.3. Qt 4 may have changed. And yes, the instantiation time
was non-trivial.
--Dave
--
[ signature omitted ]
Message 8 in thread
Daniel Albuschat wrote:
> that Qt docs and Qt examples, etc. seem to emphasize on heap-allocation
> in situations where it absolutely is not needed (nor desireable)
>
Just an interesting semi-counter-example: Just about every Qt example
program I've seen starts by allocating a widget on the stack in main().
A pedantic side note regarding semantics: Class member variables
declared as non-pointers are often referred to as "stack allocated" even
though they are really allocated wherever their owning class is
allocated. I will follow this semi-misused phraseology in the paragraphs
to follow.
My experience has been that while allocating non-pointer QObjects on the
stack works, it is often better to use the heap, simply so you can
control *when* the allocation (and subsequent constructor calls) happen.
It may be faster to perform the allocation on the stack (pointer
increment instead of memory management), but bare in mind that
allocating a C++ object implies calling its constructor too, which
always takes some time, whether on the heap or stack.
For example, if I create a QWidget-derived MyWidget class, which has
instances of FooWidget, BarWidget, and BizWidget as member variables, I
don't necessarily want my FooWidget, BarWidget, and BizWidget objects to
be instantiated every time MyWidget is instantiated, because I don't
want MyWidget to take that long to instantiate. I therefore choose to
defer instantiation until they are needed, thus improving the
instantiation time of MyWidget. If MyWidget is instantiated at
application startup time, then the application will start more quickly,
which is a Good Thing.
There's nothing worse than waiting for a GUI application to startup
simply because the author chose to naively instantiate every single
widget application-wide, even if they are not used during the life of
the application (i.e., dialogs). This is what can happen if you choose
to use non-pointer member variable QObject instances, because your code
forces the instantiation of each member to happen at the time the
"parent" object is instantiated.
I also agree with the previous poster that dynamic memory allocation is
very rarely the source of performance bottlenecks in semi-modern desktop
systems.
My $0.02.
--Dave
--
[ signature omitted ]
Message 9 in thread
2007/8/12, Dave Smith <dave@xxxxxxxxxxxxxxx>:
> Daniel Albuschat wrote:
> > Eh, why initiate MyWidget then, to begin with?
> > If you don't immediately need Foo, Bar and Biz when showing the MyWidget,
> > I totally agree that it's a good situation to use (smart-)pointers.
> >
>
> What if Foo, Bar, and Biz are widgets that only need to be shown as the
> result of user action, like launching a dialog after a mouse click?
a) I never said that you can *always* use static allocation.
Just that you don't *always* need to use dynamic allocation.
b) if the widget happens to be a QDialog that is shown modal, you can do:
void Class::on_button_clicked()
{
MyDialogWidget widget;
widget.exec();
}
If the widget is shown non-modal, you definitely use dynamic allocation
and the automatic cleanup of QObject comes in handy.
--
[ signature omitted ]
Message 10 in thread
Daniel Albuschat wrote:
> a) I never said that you can *always* use static allocation.
> Just that you don't *always* need to use dynamic allocation.
> b) if the widget happens to be a QDialog that is shown modal, you can do:
>
> void Class::on_button_clicked()
> {
> MyDialogWidget widget;
> widget.exec();
> }
>
I agree 100%, and indeed, this is how I often implement this sort of thing.
--Dave
--
[ signature omitted ]
Message 11 in thread
Daniel Albuschat wrote:
> Those both paradigms can happily live next to each other -- it's just
> that Qt docs and Qt examples, etc. seem to emphasize on heap-allocation
> in situations where it absolutely is not needed (nor desireable).
Can you be more specific and list some cases where you disagree with the
current practice?
David
--
[ signature omitted ]
Message 12 in thread
2007/8/13, David Boddie <dboddie@xxxxxxxxxxxxx>:
> Daniel Albuschat wrote:
>
> > Those both paradigms can happily live next to each other -- it's just
> > that Qt docs and Qt examples, etc. seem to emphasize on heap-allocation
> > in situations where it absolutely is not needed (nor desireable).
>
> Can you be more specific and list some cases where you disagree with the
> current practice?
For example, a simple widget with a few members 'The Qt Way' (tm):
class MyWidgetPointer: public QWidget
{
Q_OBJECT
private:
QLineEdit *le_name;
QLabel *l_name;
QVBoxLayout *layout;
public:
MyWidgetPointer(QWidget *parent): QWidget(parent),
le_name(new QLineEdit(this)),
l_name(new QLabel(this)),
layout(new QVBoxLayout(this)) {
l_name->setText("Name: ");
layout->addWidget(l_name);
layout->addWidget(le_name);
setLayout(layout);
}
};
There are a few things to notice here:
a) Using 'this' in the initialisation-list is considered potentially dangerous,
since the object is not yet fully constructed. On the other hand,
the members I
have here only use the QWidget-subpart anyways. When handling with
more complex
class-hierarchies and dependencies, this might get dangerous, though.
b) I have to type the types of the objects twice, once when declaring them and
a second time when new'ing the object.
c) Although the object's lifetime is implied to be as long as my class
lives, pointers may
lead to the conclusion that they may be NULL. When I handle objects
instead of pointers,
I KNOW that they're definitely not NULL. Using objects expresses
the object's lifetime
more clearly and is therefore easier to comprehend and work with.
d) Pointers are often simply not needed here. And one rule of thumb
for programming C++
is to use pointers as rarely as possible.
Here's the way I do it, which is, imho, conceptually better:
class MyWidget: public QWidget
{
Q_OBJECT
private:
QLineEdit le_name;
QLabel l_name;
QVBoxLayout layout;
public:
MyWidget(QWidget *parent):
QWidget(parent),
le_name(0),
l_name(0) {
l_name.setText("Name: ");
layout.addWidget(&l_name);
layout.addWidget(&le_name);
setLayout(&layout);
}
};
Regards,
Daniel Albuschat
--
[ signature omitted ]
Message 13 in thread
Daniel Albuschat schrieb:
> 2007/8/13, David Boddie <dboddie@xxxxxxxxxxxxx>:
>> ...
>> Can you be more specific and list some cases where you disagree with the
>> current practice?
>
> For example, a simple widget with a few members 'The Qt Way' (tm):
>
> class MyWidgetPointer: public QWidget
> {
> Q_OBJECT
> private:
> QLineEdit *le_name;
> QLabel *l_name;
> QVBoxLayout *layout;
> public:
> MyWidgetPointer(QWidget *parent): QWidget(parent),
> le_name(new QLineEdit(this)),
> l_name(new QLabel(this)),
> layout(new QVBoxLayout(this)) {
>
> l_name->setText("Name: ");
> layout->addWidget(l_name);
> layout->addWidget(le_name);
> setLayout(layout);
> }
> };
Although I agree with your argumentation given I think the justified
question by David was rather if you could give a link to a concrete
example in the Qt docs which in your opinion is constructed according to
the example above.
I don't know the examples given by heart right now but I remember they
tend to using stack variables, at least in the main() function, no?
Cheers, Oliver
--
[ signature omitted ]
Message 14 in thread
* On 13.08.2007 15:20, Daniel Albuschat wrote:
[...]
> Here's the way I do it, which is, imho, conceptually better:
>
> class MyWidget: public QWidget
> {
> Q_OBJECT
> private:
> QLineEdit le_name;
> QLabel l_name;
> QVBoxLayout layout;
> public:
> MyWidget(QWidget *parent):
> QWidget(parent),
> le_name(0),
> l_name(0) {
>
> l_name.setText("Name: ");
> layout.addWidget(&l_name);
> layout.addWidget(&le_name);
> setLayout(&layout);
> }
> };
But the stack order seems to be very important. My example leads to an
segmentation fault when the window is destroyed. The solution is to
transpose the two variables below.
class MyWidget : public QWidget
{
Q_OBJECT
QGridLayout m_innerLayout;
QGroupBox m_groupBox;
public:
MyWidget(QWidget* = 0);
virtual ~MyWidget();
};
MyWidget::MyWidget(QWidget* a_parent)
: QWidget(a_parent),
m_innerLayout(0),
m_groupBox(0)
{
m_groupBox.setLayout(&m_innerLayout);
}
Regards,
Lars
--
[ signature omitted ]
Message 15 in thread
Actually I like the 'The Qt Way' better. Not that is really important with the
Qt classes, since usually they do not change between two compiler runs, but
generally with your method you give up the ability to use forward declarations.
Guido
On Mon, Aug 13, 2007 at 03:20:19PM +0200, Daniel Albuschat wrote:
> 2007/8/13, David Boddie <dboddie@xxxxxxxxxxxxx>:
> > Daniel Albuschat wrote:
> >
> > > Those both paradigms can happily live next to each other -- it's just
> > > that Qt docs and Qt examples, etc. seem to emphasize on heap-allocation
> > > in situations where it absolutely is not needed (nor desireable).
> >
> > Can you be more specific and list some cases where you disagree with the
> > current practice?
>
> For example, a simple widget with a few members 'The Qt Way' (tm):
>
> class MyWidgetPointer: public QWidget
> {
> Q_OBJECT
> private:
> QLineEdit *le_name;
> QLabel *l_name;
> QVBoxLayout *layout;
> public:
> MyWidgetPointer(QWidget *parent): QWidget(parent),
> le_name(new QLineEdit(this)),
> l_name(new QLabel(this)),
> layout(new QVBoxLayout(this)) {
>
> l_name->setText("Name: ");
> layout->addWidget(l_name);
> layout->addWidget(le_name);
> setLayout(layout);
> }
> };
>
> There are a few things to notice here:
> a) Using 'this' in the initialisation-list is considered potentially dangerous,
> since the object is not yet fully constructed. On the other hand,
> the members I
> have here only use the QWidget-subpart anyways. When handling with
> more complex
> class-hierarchies and dependencies, this might get dangerous, though.
> b) I have to type the types of the objects twice, once when declaring them and
> a second time when new'ing the object.
> c) Although the object's lifetime is implied to be as long as my class
> lives, pointers may
> lead to the conclusion that they may be NULL. When I handle objects
> instead of pointers,
> I KNOW that they're definitely not NULL. Using objects expresses
> the object's lifetime
> more clearly and is therefore easier to comprehend and work with.
> d) Pointers are often simply not needed here. And one rule of thumb
> for programming C++
> is to use pointers as rarely as possible.
>
> Here's the way I do it, which is, imho, conceptually better:
>
> class MyWidget: public QWidget
> {
> Q_OBJECT
> private:
> QLineEdit le_name;
> QLabel l_name;
> QVBoxLayout layout;
> public:
> MyWidget(QWidget *parent):
> QWidget(parent),
> le_name(0),
> l_name(0) {
>
> l_name.setText("Name: ");
> layout.addWidget(&l_name);
> layout.addWidget(&le_name);
> setLayout(&layout);
> }
> };
>
> Regards,
>
> Daniel Albuschat
>
> --
> eat(this); // delicious suicide
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
--
[ signature omitted ]
Pages: Prev | 1 | 2 | Next