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?
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.
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
.
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.
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.