23
int main(void)
{
   std::string foo("foo");
}

My understanding is that the above code uses the default allocator to call new. So even though the std::string foo is allocated on the stack the internal buffer inside of foo is allocated on the heap.

How can I create a string that is allocated entirely on the stack?

trincot
  • 317,000
  • 35
  • 244
  • 286
poindexter
  • 1,269
  • 3
  • 12
  • 23
  • Let me amend that to "how can I create a std::basic_string that is allocated entirely on the stack?" – poindexter Apr 24 '09 at 14:09
  • Just to link to a similar question: http://stackoverflow.com/questions/354442/looking-for-c-stl-like-vector-class-but-using-stack-storage – Zan Lynx Jul 10 '14 at 01:00

5 Answers5

26

I wanted to do just this myself recently and found the following code illuminating:

Chronium's stack_container.h

It defines a new std::allocator which can provide stack-based allocation for the initial allocation of storage for STL containers. I wound up finding a different way to solve my particular problem, so I didn't actually use the code myself, but perhaps it will be useful to you. Do be sure to read the comments in the code regarding usage and caveats.

To those who have questioned the utility and sanity of doing this, consider:

  • Oftentimes you know a priori that your string has a reasonable maximum size. For example, if the string is going to store a decimal-formatted 32-bit integer,you know that you do not need more than 11 characters to do so. There is no need for a string that can dynamically grow to unlimited size in that case.
  • Allocating from the stack is faster in many cases than allocating from the heap.
  • If the string is created and destroyed frequently (suppose it is a local variable in a commonly used utility function), allocating from the stack instead of the heap will avoid fragmentation-inducing churn in the heap allocator. For applications that use a lot of memory, this could be a game changer.

Some people have commented that a string that uses stack-based allocation will not be a std::string as if this somehow diminishes its utility. True, you can't use the two interchangeably, so you won't be able to pass your stackstring to functions expecting a std::string. But (if you do it right), you will be able to use all the same member functions on your stackstring that you use now on std::string, like find_first_of(), append(), etc. begin() and end() will still work fine, so you'll be able to use many of the STL algorithms. Sure, it won't be std::string in the strictest sense, but it will still be a "string" in the practical sense, and it will still be quite useful.

Eric Melski
  • 16,432
  • 3
  • 38
  • 52
  • 1
    You can use many of the STL algorithms on a bare array of char on the stack, but someone suggested that and got voted down. Questioner will have to decide which features of std::string he needs... – Steve Jessop Apr 24 '09 at 10:06
  • 2
    This doesn't work for glibc's std::basic_string, it calls the Allocator's default constructor, which StackAllocator doesn't support. – poindexter Apr 24 '09 at 18:09
13

The problem is that std::basic_string has a template parameter for the allocator. But std::string is not a template and has no parameters.

So, you could in principle use an instantiation of std::basic_string with an allocator that uses memory on the stack, but it wouldn't be a std::string. In particular, you wouldn't get runtime polymorphism, and you couldn't pass the resulting objects into functions expecting a std::string.

bouvierr
  • 3,563
  • 3
  • 27
  • 32
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    I'm not sure how that would work? Exactly how do you propose to have the allocator modify the stack frame of its caller? Simply doing an alloca() in the allocator will not work because that memory would be automatically freed when the allocator returns the pointer, or when the std::string's constructor returns if the allocator was inlined. – Don Neufeld Apr 23 '09 at 23:37
  • 1
    You're absolutely right, the allocator could only work because he didn't say *where* on the stack data he wanted the string to be. The allocator would need access to a block of stack via instance data. A bit like DJB's safe string libraries (C, not C++), which use a limited block of stack space because it's a cheap and easy way to limit memory use per thread – Steve Jessop Apr 23 '09 at 23:44
  • "*where* on the stack data he wanted the string to be". I mean, "where on the stack he wanted the string data to be". And I may have misremembered DJB's code, it was a while ago I saw it. – Steve Jessop Apr 23 '09 at 23:57
4

You can't. Except...

std::string is an instantiation of

std::basic_string<class CharType, 
                  class Traits=char_traits<CharType>, 
                  class Allocator=allocator<CharType> >

You could conceivably define an Allocator class that uses alloca for memory management. This would only work if the Allocator itself, and the basic_string methods that invoke it directly or indirectly, are all inline. A basic_string object created with this allocator would not be a std::string, but it would behave (mostly) like it. However, this would be a fair amount of work for limited gains. Specifically, using this class to return values from a function would be a career-limiting move.

I have no idea why you or anyone else would want to do this.

Dan Breslau
  • 11,472
  • 2
  • 35
  • 44
  • 2
    +1, modulo the comment to my answer, that alloca doesn't really do it because std::basic_string calls down into the allocator, so it's "too late" by then to use alloca. Can't remember how alloca interacts with inlining though - maybe with brutal amounts it could just so happen to work for a particular STL implementation and compiler settings? – Steve Jessop Apr 24 '09 at 00:15
  • The compiler would need to go way out of its way to give inlined methods their own stack frame. OTOH, placing bets on that is *another* career-limiting move. – Dan Breslau Apr 24 '09 at 00:28
  • 1
    alloca isn't POSIX, so I'm not even going to consider it. As for why someone would want to do this, I point you to Eric Melski's answer. – poindexter Apr 24 '09 at 14:32
  • 1
    A use of this technique is to preserve data locality.This might be usefull when designing an AST, it is quite conceivable to decide the maximum size of a string identifier in an AST. There are probably dozens of other use cases. C++ is a perfectly suitable language to use for creating resource constrained designs. – Hassan Syed Mar 15 '11 at 10:25
  • This answer is wrong, `alloca` allocates from a functions local stack frame. Once this goes out of scope, the allocated memory is automatically released. – user1095108 Sep 18 '13 at 09:42
  • As discussed in the comments above, it's likely to work provided that there are no non-inline methods between the caller and the allocator. (I've edited the answer to emphasize this restriction.) But even if it did work, it's still a poor idea to implement this in practice. I wrote this as a thought experiment, not as a serious suggestion for someone to implement. Walking through how this _might_ work can shed some light on how `basic_string` and allocators work, and why you _can't_ do a lot with dynamic memory on the stack. – Dan Breslau Sep 18 '13 at 17:02
0

I suspect that doing such a thing would be difficult to do, I wonder why you want to do it? To allocate something entirely on the stack, the compiler needs to know at compile time what the exact size of the thing is - in your example it would need to know not only the size of the std::string metadata, but also the size of the string data itself. This isn't too flexible, you would probably need different string types depending on the size of the string data you are wanting to include in it - not that it would be impossible to do, just it would tend to complicate things up a bit.

1800 INFORMATION
  • 131,367
  • 29
  • 160
  • 239
  • 1
    "you would probably need different string types depending on the size of the string data you are wanting to include in it". Welcome to Symbian! – Steve Jessop Apr 23 '09 at 23:36
-3
  • std::string will always manage it's internal storage with new/delete.
  • Not sure why your question contains glibc’s string implementation. The string implementation of the c++ standard library has nothing to do with glibc.
  • The only way to store a string on the stack is to use a C char array on the stack (like what Shhnap outlined). But that's probably not what you want anyway :-)
lothar
  • 19,853
  • 5
  • 45
  • 59
  • Is there really something in the standard regarding the first point.. AFAIK, the internal implementation is free to do small string size optimisations and not involve heap. – rama-jka toti Apr 23 '09 at 23:26
  • 2
    Majkara is correct, small strings(<16 chars in the MSVC implementation) are usually allocated on the stack and don't involve any heap memory allocation. – newgre Apr 23 '09 at 23:36
  • std::string defines the interface not the implementation. I'm specifically asking about the glibc implementation because it's what I'm working with. If I was using the MSVC implementation I wouldn't be asking this question. Fortunately I've been provided with an answer that is implementation independent. – poindexter Apr 24 '09 at 14:45
  • 1
    @poindexter glibc does NOT have a std::string implementation. it's in libstdc++ from gcc. – lothar Apr 24 '09 at 17:12
  • @Majkara Tito The fact that the implementation of some compilers do small string size optimisations does not mean that you can write (portable) C++ where your string is not hep allocated. – lothar Apr 24 '09 at 17:14