views:

508

answers:

6

I was looking for a rule of thumb for allocating objects on stack or heap in C++. I have found many discussions here on SO. Many people said, it's about the lifetime of an object. If you need more lifetime than the scope of the function, put it in the heap. That makes perfect sense.

But what made me confusing is, many people said, allocate objects to stack if they are small. If objects are big, put it to heap. But none of them said how to identify an object is big or not?

I have the following questions,

  1. How to identify an object is big or not?
  2. What will be the stack maximum size? Each OS will have different stack size?
  3. I have a wrapper class which wraps vector<string>. It will have around 100 items. Will it make a stack overflow if I allocate this class to a stack? I tried this, but it worked perfectly. Not sure I am doing something wrong.

Any thought?

Thanks

+3  A: 

According to MSDN stack size defaults to 1mb. (This is for Msdev obviously).

As you can see from the article, you can modify the stack size at compile time with the /F flag.

I think your first guideline for stack vs heap usage is pretty accurate, with the qualification that if you temporary scope variable is bigger than a mb, stick it on the heap (and probably ask why you are allocating so much memory for a short period of time in the first place).

Cannonade
+1  A: 

How to identify an object is big or not?

Depends on your compiler/platform combo. There is no One True limit. Compilers often allow you to tune this.

What will be the stack maximum size? Each OS will have different stack size?

Depends mostly as above. Only thing you have less control of tuning.

I have a wrapper class which wraps vector. It will have around 100 items. Will it make a stack overflow if I allocate this class to a stack? I tried this, but it worked perfectly. Not sure I am doing something wrong.

Will work as long as the total memory requirement of this wrapper and other objects in that block does not exceed your stack frame size. Which in turn depends on the average string sie.

A good idea is to step through a debugger and see the stack addresses -- that'll give you a start of the width to some extent. And the documentation.

dirkgently
+9  A: 

Well firstly vectors (and all the STL container classes) always allocate from the heap so you don't have to worry about that. For any container with a variable size it's pretty much impossible to use the stack.

If you think about how stack allocation works (at compile time, basically by incrementing a pointer for each object) then it should be clear that vector memory comes from the heap.

std::vector<int> myInts;
std::string myString;
SomeOther Class;

// this memory must come from the heap, there's no way it
// can now be allocated on the heap since there are other
// objects and these parameters could be variable
myString = "Some String";
myInts.reserve(256);

Unless you are in a recursive function you can place several kilobytes of data on the stack without much worry. Stack-sizes are controlled by the program (not the OS) and the default tends to range from 32kb - 1mb. Most desktop software comes in at the 1mb range.

Individual objects are almost never a concern. In general they will either be small enough for the stack, or will allocate internally from the heap.

If objects are local to a function put them on the stack. If not put them on the heap.

Use the heap for large buffers you allocate for loading/sorting/manipulating data.

Andrew Grant
... for loading/sorting/manipulating data *manually*. If you're using STL to do the work for you, there's no need to go through the trouble and bother with new/delete. Just allocate on the stack there.
strager
Thanks for the answer. Do you have any document where it says vector allocates contents on a heap?
Appu
It has to for .resize() etc. to work.
Simon Buchan
I've updated my answer to demonstrate why vector (and collections in general) must allocate from the heap.
Andrew Grant
That makes perfect sense. Thanks
Appu
Two nitpicks (1) A vector and string may contain a small initial buffer which they use to avoid heap allocations, in string this is known as the small string optimization and in vectors I don't know if any implementation actually uses this optimization. (2) It doesn't matter how much stuff you put on the stack (as long as it's less than the stack frame) during recursion the whole stack frame is pushed even if not all of it is used.
Motti
+1  A: 

One more point I'll mention is that because vector<> must be able to resize itself, if it grows large enough (see below) it must use the heap for storing its contained objects, even if the vector<> itself is declared as a stack variable.

[EDIT] As Motti points out in a comment, it's possible that vector<> reserves a small amount of space inside its stack-allocated object as an optimisation for small vectors. In that case, working with vectors small enough to fit inside this space will not require any heap allocations. (This pre-allocated space must be quite small to avoid wasting space when working with smaller vectors.) Regardless, if the vector grows sufficiently large, it will require (re-)allocation on the heap.

j_random_hacker
Not true, it may use an initial buffer that's part of the object (like the small string optimization).
Motti
Good point. I've updated the post to clarify things.
j_random_hacker
+3  A: 

The only way you can allocate large objects on the stack is to have an old-style array involved at some point. For example:

void f() {
   char a[1000000];    // big object on the stack
}

struct A {
   char c[1000000];
};

void g() {
   A a;      // another big object on the stack
}

If you don't use arrays (and you shouldn't) then most things will be allocated for you on the heap:

void h() {
   std::string s( 100000 );
}

the above allocates a few bytes on the stack for pointers, size info etc. and then allocates the actual storage on the heap.

So stop worrying! You are probably doing things right!

anon
Those aren't "old-style arrays." They are arrays. You shouldn't never use them, and you should know how (and when) to use them.
strager
Thanks for the answer. But how come the last code you have given goes into heap? Do you mean to say std::string uses heap internally to keep the contents?
Appu
@Appu Yes, precisely
anon
+1  A: 

1. How to identify an object is big or not?

Use "sizeof"

class c {
  std::vector<std::string> s;
};

int size = sizeof(c);

On my machine "size" is 16 bytes.

2. What will be the stack maximum size? Each OS will have different stack size?

You can't tell, but it's definitely not a good place to allocate masses of data.

3. I have a wrapper class which wraps vector. It will have around 100 items. Will it make a stack overflow if I allocate this class to a stack? I tried this, but it worked perfectly. Not sure I am doing something wrong.

No. std::vector allocates the 100 items in the heap.

Jimmy J