Re: Memory : Stack vs Heap
On 26 Maj, 22:54, coder_...@yahoo.com wrote:
I think my "real" C++ neutrons are starting to fire:) Well, up until
recently, I have always used C++ like a super C with classes. That
is, copy constructor/assignment operators were always private and all
object instantiation were done with "new", so I knew exactly when and
where an object was, ie. heap or stack. Now, that I started to use
Array templates, I find that "natural" (no pointers?:)) code looks and
feel best. Ie...option 1 below looks better than option2
1. Array<int32> ia(10); ia[0] = 100;
2. Array<int32> *ia1 = new Array<int32>(10); (*ia1)[0] = 100;
It certainly does. Also it is faster with one less allocation. What
confuses you is perhaps that the
Well, option 1 opened up a can of wormy questions for me:) So, if I
understood things right, the memory space for class members is the
same memory space as the containing class. Ie. if the containing
class is all in heap, then all members (recursively) will be on heap.
Yes. A member of an object will always be in the same location as the
object itself.
The pointer "data" in your original class is a member of your class,
so if the Array<> is placed on the heap then so will data. What might
confuse you is that what data points to does not belong to your class.
It is owned by your class, but it is not part of it. And that data is
allocated via new and will thus always be on the heap.
Well,
class X
{
X(){}
void myFunc() { ia = Array<int32>(10);}
Array<int32> ia;
};
int main()
{
X x;
}
Please help (I perused a few books, but I could not find a definitive
answer):
1. ia will first be instantiated with the default constructor in X(),
and that copy will be thrown away and replaced with a new copy in
myFunc()? That seems a bit wasteful. With a pointer, I would not
have to instantiate ia until I need to allocate space for me.
This is correct. There will be a copy, and the original Array will be
thrown away. Thus, the statement:
ia = Array<int32>(10);
will create a temporary Array with ten copies in it, invoke your
assignment operator and destroy the temporary Array. This is two calls
to new + the overhead with copying the elements.
But you can avoid this by using a neat trick - namely by swapping. You
should write a new procedure that swaps two Arrays - something like:
template <typename T>
void swap(Array<T>& one,Array<T>& other)
{
std::swap(one.data,other.data);
std::swap(one.dataLen,other.dataLen);
}
This will not work out of the box as e.g. you don't have access to
data and dataLen which are private, so you would have to make swap a
member function, and you would also have to create a swap function for
your baseclass (and there is more work to to if you want to make swap
available to others in a generic fashion). Still this should give you
an idea of how to do it.
The upcoming C++ standard (C++0x) is going to solve some of these
problems via move constructors. You will still have to do write the
move constructor yourself, however.
2. Will x be on the stack? And will ia be on the stack too? But if X
contained other members and those members contained yet other member
objects, wouldn't we run the risk of inadvertently blow the stack?
Yes they will both be on the stack, but remember the objects are not
that large. Array<T> uses no more than eight bytes if I guess your
architecture correctly, so that is only 16 bytes of stack storage. In
general, objects do not get that large, and I would not worry about
such stuff if I were you.
3. From 2, so to avoid blowing the stack, main() should start with a X
*x = new X() ? So that all subsequent allocations will all be on the
heap?
That would save you eight bytes of stack storage, but it will cost
more heap storage and so it is a bad idea. Using pointers not only
looks more kludgey, it will also give you lots of problems with regard
to e.g. exception safety, and in general there will be lots of
housekeeping to do.
One last thing worth mentioning is to always initialise in your
constructor.
Array<int> ia;
ia = Array<int>(10);
is two calls to new, and one copy.
Array<int> ia(10);
does the same and is half the work.
Of - and one more thing: Do use std::vector for your normal work.
std::vector is thoroughly tested and much more flexible than your
Array class, and it only uses twelve bytes of storage on your
architecture (unless I guessed wrong again). Also, all of the
infrastructure - such as swapping - is already in place.
/Peter