Re: alloca / _alloca / dynamic stack memory
On Thu, 8 Mar 2007 22:24:00 -0800, Michael Crawley
<MichaelCrawley@discussions.microsoft.com> wrote:
Lets assume we have a String class with an internal char* pointer and an
unsigned integer for the length. This class has a fixed size. Upon
constructing an instance of this type, we pass a variable-sized const char*
that will be copied and set to the internal char*. So if we used the default
new operator, we would be looking at two calls to malloc indirectly...which
means the thread had to compete for a shared lock defined within malloc
twice.
So, String looks like this:
class String : Object
{
unsigned len;
char* p;
};
Looks a lot like std::string, modulo the small-string optimization
introduced a couple of versions ago in VC++.
By allocating an instance of String class using new(StackAlloc)
operator, we only have to call malloc once when we perform an internal copy
of const char* to be stored in our internal char* pointer. This might allow
for a small perf gain by itself, but if done thousands of times, it can add
up. If a heap has been allocated on a per-thread basis, of course use the
that heap.
It seems like you can accomplish the same thing by using a local
std::string variable:
void f(const char* str)
{
std::string s(str);
}
Why would I want to write this as:
void f(const char* str)
{
String* s = new (StackAlloc) String(str);
}
You've stated that the copy of the data is going to be on the heap, just
like when you use a local variable. Because your approach adds a pointer
variable to hold the address of the String object on the stack, your
approach actually uses more of the stack than using a plain old local
variable. In addition, you have to worry about destroying the string, while
this is handled automatically when you use a local variable. I see only
disadvantages to what you're proposing.
Okay...so what about arrays. No problem... If we go "String* str =
new(StackAlloc) String[N]" we should get this array allocated on the stack
dynamically...for each item in the array, the default constructor is
called...
This I recognize as a new capability. I'm not sure it would be useful,
since each String is going to have to go to the heap, so you will have
eliminated only one call to the heap manager.
<snip>
The remainder was more exposition along the lines of what you posted
already. What I was looking for is the definition of the String class,
particularly the parts that use the Object facilities. For now, I'll just
assume Object does everything you want. How does String use it? Code such
as the following just reiterates what you've already shown concerning how
people use String:
String* str = new String("msdn"); // (sizeof(String) + 1byte header)
String* str1 = new(Heap) String("msdn"); // (sizeof(String) + 1byte header +
sizeof(void*) ref to heap)
String* str2 = new(StackAlloc) String("msdn"); // (sizeof(String) + 1byte
header)
delete str; // Compiler emits destructor; Look in header; oh it's on the
default heap, free(str)
delete str1; // Compiler emits destructor; Look in header; oh it's on this
heap, heap->Deallocate(str)
delete str2; // Compiler emits destructor; Look in header; oh it's on the
stack, do nothing. deallocation happens when function returns
What I want to know is how String uses Object. Here's what I thought you
were trying to accomplish. You're trying to eliminate calls to the heap
manager, be it malloc or whatever. To that end, you want to create a class
that can be created only with new, yet it should allow allocation of all
its data on the stack, or on the heap, depending on how you write the
new-expression. I could imagine this being a sort of generalization of VC's
small-string optimization for std::string. But now I'm confused, because
you've described your String class as using the heap for its data, so it's
not what I thought. The array usage you described would be useful only for
simple types, so now it sounds like you're asking for dynamic arrays.
--
Doug Harrison
Visual C++ MVP