Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!microsoft!jimad From: jimad@microsoft.UUCP (Jim ADCOCK) Newsgroups: comp.std.c++ Subject: Re: Creeping feature #769: `new auto' Keywords: dynamic stack allocation, alloca Message-ID: <72915@microsoft.UUCP> Date: 14 Jun 91 19:29:44 GMT References: <1991May2.074928.25507@kestrel.edu> <12759@exodus.Eng.Sun.COM> <1991May27.233808.14632@hal.com> Reply-To: jimad@microsoft.UUCP (Jim ADCOCK) Distribution: comp.std.c++ Organization: Microsoft Corp., Redmond WA Lines: 134 In article <1991May27.233808.14632@hal.com> shap@hal.com (Jonathan Shapiro) writes: >Until recently, I was inclined to agree with you. Since then, I have >run into at least one case where the need to use malloc/free becomes >impossibly cumbersome: functions that do error recovery or error-based >abandonment. > >Consider a function that does the following: > > allocate something > > conditionally return failure > > allocate something else > > conditionally return failure > > allocate something else > > deallocate everything > return success > >In the absence of alloca(), the management of deallocation becomes a >very likely source of programmer error, especially as the function is >maintained by third parties. > >In my view, this is a compelling reason to have alloca. I disagree. Its easy to solve the kinds of problems that alloca can solve from within C++ -- see the following simple-minded example. Alloca simply allows one to create variable sized objects of known lifetime [namely the lifetime of the surrounding routine] and this is not a hard problem anyway. Rather, the hard problem is managing the deallocation of objects of indefinite lifetime, which in general is not a solvable problem excepting the use of garbage collection. To which I propose: Garbage Collection. Given garbage collection, any advantages of alloca go away anyway, since GC schemes exist where allocation simply becomes an inline ptr addition -- which is as efficient or better than alloca anyway. ---- extern "C" { #include #include #include } void* traced_malloc(size_t size) { void* p = malloc(size); printf("allocate %d bytes at $%lX\n", size, (long)p); return p; } void traced_free(void* p) { printf("free at $%lX\n", (long)p); } void* operator new(size_t size) { return malloc(size); } void operator delete(void* p) { free(p); } #define malloc(x) traced_malloc(x) #define free(x) traced_free(x) int failed() // simulate unpredictable failures { return !(3 & rand()); } class Tracker { public: void* p; operator void*() { return p; } Tracker(void* pT) : p(pT) {} Tracker() : p(0) {} ~Tracker() { if (p != 0) free(p); } }; #define FAILURE 1 #define SUCCESS 0 int troublesome_routine() { // allocate something: Tracker p1 = malloc(100); // conditionally return failure: if (failed()) return FAILURE; // allocate something else: Tracker p2 = malloc(200); // conditionally return failure: if (failed()) return FAILURE; // allocate something else: Tracker p3 = malloc(300); // conditionally return failure: if (failed()) return FAILURE; // trackers will automatically deallocate everything, so just: return SUCCESS; } // lets try these "troublesome" routine a few times and see what happens: main() { for (int tries=0; tries<10; ++tries) { printf("----------------------\n"); troublesome_routine(); } } // ---- its no trouble at all!