stack variables that don't die?

D

Dougan

I've seen code that allocates an object on the stack and then saves a
class reference to it.

example:
void ScribbleArea::resizeImage( const QSize &newSize)
{
QImage newImage( newSize, );
*m_image = newImage; // m_image is a QImage
}

Now, when c++ leaves the function, I guess the stack memory for
newImage
is not reclaimed, because the object is still referenced?

If this is correct, when, if ever. is the memory in the stack
reclaimed?

If this function were called many times, woudn't this lead to
leaks in the stack, if that is possible?
 
I

Ian Collins

Dougan said:
I've seen code that allocates an object on the stack and then saves a
class reference to it.

example:
void ScribbleArea::resizeImage( const QSize &newSize)
{
QImage newImage( newSize, );
*m_image = newImage; // m_image is a QImage
}

Now, when c++ leaves the function, I guess the stack memory for
newImage
is not reclaimed, because the object is still referenced?
No, it will be reused, but you have made a copy of it.
If this is correct, when, if ever. is the memory in the stack
reclaimed?
This can't leak memory, you don't use the heap, unless QImage leaks memory.
 
S

Salt_Peter

no, m_image is a pointer and we don't know if thats an allocated
pointer.
newImage is a temporary QImage.
No, it will be reused, but you have made a copy of it.

Are you sure? What if the member pointer was never allocated? That
would be a copy into unreserved memory. So between resizes, the
temporary image would be copied into unprotected memory?
Please tell me i'm wrong. Otherwise, thats undefined behaviour and one
very nasty bug to crack.
 
I

Ian Collins

Salt_Peter said:
Are you sure? What if the member pointer was never allocated? That
would be a copy into unreserved memory. So between resizes, the
temporary image would be copied into unprotected memory?
Please tell me i'm wrong. Otherwise, thats undefined behaviour and one
very nasty bug to crack.
Who knows? I was assuming the pointer was valid and the OP was simply
replacing the object. Otherwise the operation does invoke UB.
 
S

Salt_Peter

Ian said:
Who knows? I was assuming the pointer was valid and the OP was simply
replacing the object. Otherwise the operation does invoke UB.

After verification and for the record, Qt's recommendation is to have
class ScribbleArea hold a QImage component, not a pointer. Now that
makes sense to me if QImage has the appropriate copy constructor. Hmm.
http://doc.trolltech.com/4.1/widgets-scribble-scribblearea-h.html

To the OP, pointers - unless proven otherwise - point to nothing at all.
 
K

Kaz Kylheku

Dougan said:
I've seen code that allocates an object on the stack and then saves a
class reference to it.

Does it?
example:
void ScribbleArea::resizeImage( const QSize &newSize)
{
QImage newImage( newSize, );
*m_image = newImage; // m_image is a QImage
}

This can't possibly save a reference, unless m_image is a pointer to a
class object which has an overloaded assignment operator (a member or
non-member one). That is to say:

// Suppose this is m_image:
SomeObject *m_image;

// And suppose this the assignment op
void SomeObject::eek:perator = (QImage &ref);

Similarly, m_image could be a smart pointer rather than an ordinary
pointer, with the same effect.

The only other way a reference could be taken would be if the
expression *m_image were in fact a reference. That would mean that
m_image is a pointer to a reference. But, you probably know that there
is no such thing in C++: you can't point at a reference.
Now, when c++ leaves the function, I guess the stack memory for
newImage
is not reclaimed, because the object is still referenced?

The C++ language does not have lexical closures, nor does the C++
standard mandate the support for garbage collection. Any use of an
non-static local object whose scope has terminated is undefined
behavior.

The C++ language does require the destructors to be called.
If this is correct, when, if ever. is the memory in the stack
reclaimed?

The destructors, if any, are called when the activation associated with
the enclosing block scope terminates. The memory can be reclaimed any
time after that, and typically that is done right away, since in the
typical C++ implementation, a simple linear stack is in fact used as
the basis for automatic storage.
If this function were called many times, woudn't this lead to
leaks in the stack, if that is possible?

In languages which allow local variables to endure after the
termination of the enclosing block, this problem is taken care of by
garbage collection (or in less mature technology of that ilk, by
reference counting).

Note that in these languages, such as Scheme or Common Lisp, there
aren't any pointers. So the only way you can actually access a variable
in a block scope which has terminated is to invoke a closure which was
created in that block. The closure internally holds a reference to a
piece of code, and a reference to the environment frame which was saved
(the piece of the stack that was "leaked", but not really). That frame
pointer allows the closure to reference the variables.

In these languages, therefore, support for closures is the only reason
why variable bindings survive block scope termination. Good compilers
for these languages analyze and optimize closures. When closures are
not used in a function at all, all of its local storage can be
allocated on a stack, just like in C or C++, which can be a major
performance gain: if you don't use it, you don't pay for it. But even
if closures are present, this optimization may still be possible if the
closures are not escaping: the closures are only passed down into code
but not returned (in jargon, the code uses downward funargs only).
Closures which are not passed anywhere can even be refactored locally
and disappear. E.g. (funcall (lambda (x) (print x)) 42) is the same as
(let ((x 42)) (print x)) which can be hacked all the way down to (print
42).
 
S

Salt_Peter

Ian said:
Who knows? I was assuming the pointer was valid and the OP was simply
replacing the object. Otherwise the operation does invoke UB.

After verification and for the record, Qt's recommendation is to have
class ScribbleArea hold a QImage component, not a pointer. Now that
makes sense to me if QImage has the appropriate assignment operator.
Hmm.
http://doc.trolltech.com/4.1/widgets-scribble-scribblearea-h.html

To the OP, pointers - unless proven otherwise - point to nothing at all.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top