Dougan wrote:
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::operator = (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).