I just came across a problem where the constructor of a class needs to allocate memory. So I happily wrote char *mem = static_cast<char*>(malloc(100*sizeof(*mem)));
. But then I suddenly realized that in case of error I can't return error code (I am not using exceptions in my code). How ca开发者_JS百科n I solve this problem?
Should I add an bool initialized
member and then after making my class and then check it right after, as in:
myClass mc;
if (!mc.initialized) {
printf("Memory allocation failed in mc's constructor\n");
exit(1);
}
Thanks, Boda Cydo.
You should use new, not malloc. new throws std::bad_alloc when you are out of memory. An exception should be propagated from the constructor if you fail to allocate (or for any other reason have a problem with initialization), as this is the only way you prevent the destructor from being called. If the constructor successfully completes, the destructor must be called (unless, of course, it was heap allocated and never freed).
That's what exceptions were invented for. Also, use new
instead of malloc(3)
.
If you're not using exceptions, you shouldn't use constructors (or shouldn't write constructors that can fail), because as you've noticed, there is no way to report an error from a constructor except via an exception. You can alternately use a factory function and use that to decouple the bits that can fail from the bits that can't
class myClass {
private:
char *m_malloced_buffer;
// disallow calling ctors/dtors directly
myClass(char *malloced_buffer) : m_malloced_buffer(malloced_buffer) {}
~myClass() { free(m_malloced_buffer); }
public:
static myClass *create()
{
char *buf = static_cast<char*>(malloc(100*sizeof(*mem)));
if(!buf) return NULL;
void *myClassRes = malloc(sizeof(myClass));
if(!myClassRes) return NULL;
new (myClassRes) myClass(buf); // placement new, uses existing memory to invoke the ctor
return static_cast<myClass*>(myClassRes);
}
static void destroy(myClass* val)
{
if(!val) return;
val->~myClass(); // explicitly invoke dtor
free(val); // deallocate memory
}
};
...
myClass *val = myClass::create();
if(val) { ... }
myClass::destroy(val);
In this example I've used malloc and free to do all the allocating, you could use new (std::nothrow) and delete just as easily. You'll have to extract every operation that can fail out of your ctor and into the factory function so that you can check for errors without using exceptions. Even in this simple example, you can see this is a huge pain in the neck. You say you learned that "exceptions are not good coding style" in a comment, do you mean you learned that (whether by instruction with reasoned arguments and explanations, or from experience), or someone said "exceptions are not good coding style" and you've accepted the statement as dogma?
Using a bool initialized member leads to the zombie object problem (see http://www.parashift.com/c++-faq-lite/exceptions.html).
If you're using C++ and not C you should probaly be using new instead of malloc. Throwing an exception is probably what you want to do from within your constructor.
If you're using new (nothrow) though because you don't want an exception,or you are using malloc then you can simply test the pointer that is returned for NULL. You would then set a member variable which indicates that the object is in a failed state. This is seen in streams classes of the standard C++ library.
精彩评论