Multiple serial-dependent allocations

Started by
23 comments, last by Jan Wassenberg 18 years, 9 months ago
Hi everyone, please consider this (maybe frequent) C/C++ code:


/* GLOBALS (or class members, or whatsoever...) */

SomeType1 * pT1 = 0;
SomeType2 * pT2 = 0;
/* ... */
SomeTypeN * pTN = 0;

bool MyInitFuncion(void) {
	pT1 = new SomeType1[/* ..size1.. */];
	if (!Check_Or_Use_T1(pT1)) {
		return (false);
	}

	pT2 = new SomeType2[/* ..size2.. */];
	if (!Check_Or_Use_T2(pT2)) {
		delete pT1;
		return (false);
	}

	/* ... */
	/* ... */
	/* ... */

	pTN = new SomeTypeN[/* ..sizeN.. */];
	if (!Check_Or_Use_TN(pTN)) {
		delete pT1;
		delete pT2;
		/* ... */
		/* ... */
		/* ... */
		return (false);
	}

	return (true);
}



As you can see, this code, thus it seems robust (well, at least to me), could be error-prone and quite unpratical. Here is the most-seen solution i've found:


bool MyInitFuncion(void) {
	pT1 = new SomeType1[/* ..size1.. */];
	if (!Check_Or_Use_T1(pT1)) {
		goto my_error;
	}

	pT2 = new SomeType2[/* ..size2.. */];
	if (!Check_Or_Use_T2(pT2)) {
		goto my_error;
	}

	/* ... */
	/* ... */
	/* ... */

	pTN = new SomeTypeN[/* ..sizeN.. */];
	if (!Check_Or_Use_TN(pTN)) {
		goto my_error;
	}

	return (true);

my_error:
	delete pT1;
	delete pT2;
	/* ... */
	/* ... */
	/* ... */
	delete pTN;

	return (false);
}



But "goto"... quite ugly although functional :P Another solution could be to group each runtime allocated pointer (object or array...) into a class/struct and then call a specific free funcion:


void Clean(MyGlobalStruct * pGlobal) {
	delete pGlobal->pT1;
	delete pGlobal->pT2;
	/* ... */
	/* ... */
	/* ... */
	delete pGlobal->pTN;
}

bool MyInitFuncion(void) {
	my_global_struct->pT1 = new SomeType1[/* ..size1.. */];
	if (!Check_Or_Use_T1(my_global_struct->pT1)) {
		Clean(my_global_struct);
		return (false);
	}

	my_global_struct->pT2 = new SomeType2[/* ..size2.. */];
	if (!Check_Or_Use_T2(pT2)) {
		Clean(my_global_struct);
		return (false);
	}

	/* ... */
	/* ... */
	/* ... */

	my_global_struct->pTN = new SomeTypeN[/* ..sizeN.. */];
	if (!Check_Or_Use_TN(my_global_struct->pTN)) {
		Clean(my_global_struct);
		return (false);
	}

	return (true);
}



Consider these examples with explanatory purpose only (substitute operator new with malloc() and delete with free() or every language-specific memory allocation, though the alloc/free code can be seen as generic initialize/finalize code). Some opinions? Thanks :) [Edited by - CoreMeltdown on July 17, 2005 5:51:54 AM]
Advertisement
Whenever I use a pointer in a function, I normally use a std::auto_ptr, as it will take care to delete the memory for me (however, be carefull with arrays).

If I need to store that pointer in a class and the class may get copied, I will use a boost smart pointer or even a Loki one, which will take care of it all for me.
hi desertcube.
thanks for your reply, but IMO it's not focused on my problem, maybe I wasn't clear enough.
The problem is not in pointers' scope.
Say, you have some piece of data you can initialize/finalize.
You initialize a certain datum only if all previous data have been well initialized. If something goes wrong with your last initialization you have to "finalize" all previously-initialized data.
No, my post was related. Basically you let a class's constructor/destructor take care of it for you.

For example, say you were dealing with the Win32 API GlobalAlloc, you may want to encapsulate this into a class as follows:
template <class T>struct GlobalMemory{    GlobalMemory() {_storage = (T *)GlobalAlloc(GMEM_FIXED, sizeof(T));}    ~GlobalMemory() {GlobalFree(_storage);}    T * operator->() {return _storage;}private:    T * _storage;};


HTH
Probably the nicest version of your code would use smart pointers and look something like this:
bool MyFunction(){    boost::shared_array<MyType> p1(new MyType[123]);    if(!CheckAndUse(p1)) return false;    boost::shared_array<MyType> p2(new MyType[123]);    if(!CheckAndUse(p2)) return false;    boost::shared_array<MyType> p3(new MyType[123]);    if(!CheckAndUse(p3)) return false;    return true;}


See: boost::shared_array


Of course, the bunch of if statements looks like it could be worthy of exceptions too, but that will depend on what you're actually doing.
Quote:Original post by CoreMeltdown
thanks for your reply, but IMO it's not focused on my problem, maybe I wasn't clear enough.
The problem is not in pointers' scope.


Actually, if you use std::auto_ptr, it will be.
std::auto_ptr automatically deletes whatever object it points to, when it goes out of scope:
std::auto_ptr<SomeType> ptr1 = 0, ptr2 = 0, ptrn = 0;bool MyInitFunc(){if (!(ptr1 = new SomeType()))return false;if (!(ptr2 = new SomeType()))return false;if (!(ptr3 = new SomeType()))return false;return true;}

so when you call 'return', anywhere in your function, all of the auto_ptrs will go out of scope, and delete the object they point to.

edit: beaten to it [wink]

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I am sorry...
consider a C version of my code...
Quote:Original post by swiftcoder
Quote:Original post by CoreMeltdown
thanks for your reply, but IMO it's not focused on my problem, maybe I wasn't clear enough.
The problem is not in pointers' scope.


Actually, if you use std::auto_ptr, it will be.
std::auto_ptr automatically deletes whatever object it points to, when it goes out of scope:
*** Source Snippet Removed ***
so when you call 'return', anywhere in your function, all of the auto_ptrs will go out of scope, and delete the object they point to.

edit: beaten to it [wink]


yes you're right... but the auto_ptr you used are declared globals..
Maybe I don't catch you well.... but as far as i know your code snippet cause all allocated pointers to remain allocated once the funcion returns..
Quote:Original post by CoreMeltdown
I am sorry...
consider a C version of my code...


So you want to do it in C, then? No classes, no deconstructors, no RAII, no exception safety, no operator new (then why did you use it)?

In that case, one of your methods in your first post will probably do. I'm sure someone with more plain-C experience can suggest the most elegant method.
Quote:Original post by Andrew Russell
Quote:Original post by CoreMeltdown
I am sorry...
consider a C version of my code...


So you want to do it in C, then? No classes, no deconstructors, no RAII, no exception safety, no operator new (then why did you use it)?

In that case, one of your methods in your first post will probably do. I'm sure someone with more plain-C experience can suggest the most elegant method.


Well, however, even if i claimed a plain C anwer, the auto_ptr doesn't solve the problem.

Your solution
std::auto_ptr<SomeType> ptr1 = 0, ptr2 = 0, ptrn = 0;bool MyInitFunc(){if (!(ptr1 = new SomeType()))return false;if (!(ptr2 = new SomeType()))return false;...


if, for example, the second "if" condition is not satisfied, does not deallocate ptr1

This topic is closed to new replies.

Advertisement