Quote:Original post by paulecoyote
the same would happen if you used a std::string declared in a function. It would get created and destroyed, but allocated and deallocated quickly.
Sort of. If the std::string implementation includes a short string optimization, and none of the converted ints exceed that buffer length (and it's normally 16 chars or so, so they shouldn't), then yeah, everything gets iteratively pushed on and off the stack. Otherwise, the string would dynamically allocate and free memory for its buffer for every number. The difference being that the std::string would be forced to deallocate every iteration, while a GCed language will do it when it feels like doing it.
Note that putting things onto the heap doesn't necessarily cost so much in a GCed language. The allocation isn't done like malloc() with a free-list or anything; it will instead treat memory more or less like a stack. Most GC passes, the ones that scrape only the "young" generation, will effectively do the same; when full GC happens, objects get shuffled around and compacted, so that instead of leaving "holes" in memory that couldn't be used (unless you tracked them, in which case you'd be back to slow malloc-style heap allocation), all the memory is sifted to the top. (It can do this because it knows exactly which bits of object memory are pointers and which aren't, so it knows what's in use, and also what to change if it wants to move objects around).
Beware, if you use 'unsafe' C# code to "hide" a pointer, and GC happens before you can "reveal" it - kaboom. Just don't freakin' do it, ok? :) That's why it's called 'unsafe'.