views:

152

answers:

9

Some of my code still uses malloc instead of new. The reason is because I am afraid to use new because it throws exception, rather than returning NULL, which I can easily check for. Wrapping every call to new in a try{}catch(){} also doesn't look that good. Whereas when using malloc I can just do if (!new_mem) { /* handle error */ }.

Therefore I have a question. Can I use smart pointers together with malloc?

Something like:

SmartPointer<Type> smarty = malloc(sizeof(Type));

Something like this.

Is this possible?

Thanks, Boda Cydo.

+1  A: 

It depends on what the SmartPointer does on destruction. If you can specify free as a deallocator, that could work. For example, boost::shared_ptr allows you to specify a deleter.

I didn't pay enough attention to your reason for wanting this. I agree with the other answers that using the nothrow new is a much better idea.

Fred Larson
+1  A: 

It is possible to use malloc with smart pointers (you have to cast return value to target pointer type, though and provide custom deallocator). But better option is to use nothrow version of new operator.

http://www.cplusplus.com/reference/std/new/nothrow/

el.pescado
+7  A: 

You can use nothrow keyword with the new operator, which will return NULL rather that throw an exception. For details see link below: http://www.cplusplus.com/reference/std/new/nothrow/

gtikok
Is using `nothrow` a common practice? (Because I haven't actually seen personally use of nothrow in real practice myself.)
bodacydo
It is the most common way to use `new` when you don't want it to throw an exception. But no, it is more common to just use `new` and work *with* exception handling. If allocation fails, you can't usually do much about it anyway, so letting an exception propagate is a pretty clean way to exit gracefully.
jalf
+3  A: 

If you are using shared_ptr or unique_ptr, you can specify a custom deleter. For example,

struct free_delete
{
    void operator()(void* x) { free(x); }
};

This can be used with shared_ptr like so:

std::shared_ptr<int> sp((int*)malloc(sizeof(int)), free_delete());

If you are using unique_ptr, the deleter is a part of the unique_ptr's type, so the deleter needs to be specified as a template argument:

std::unique_ptr<int, free_delete> up((int*)malloc(sizeof(int)));

However, it is better to use exceptions correctly, rather than avoiding them, when writing C++, especially with respect to allocation failures. In most cases, you cannot successfully recover from an allocation failure in the function trying to do the allocation, so exceptions can help you to handle the error where you are actually capable of handling it.

James McNellis
+1  A: 

What code goes in /* handle error */? Is there anything you can actually DO with an out-of-memory error? I just let the application terminate with a call stack (core dump) so I have an idea at least one possible place that might be causing problems.

Using malloc to allocate memory for C++ classes and objects is not a good idea because it won't make sure that the constructors are called, possibly leaving you with uninitialized classes that may even crash if they have virtual methods.

Just use new and delete and don't worry about catching the exception, after all running out of memory IS an exceptional case and should not happen in normal runs of the application.

Mark B
A: 

You might want to try "placement new". See http://stackoverflow.com/questions/222557/cs-placement-new

Kristopher Johnson
A: 

Use nothrow.

Nothrow constant

This constant value is used as an argument for operator new and operator new[] to indicate that these functions shall not throw an exception on failure, but return a null pointer instead.

char* p = new (nothrow) char [1048576];
if (p==NULL) cout << "Failed!\n";
else {
    cout << "Success!\n";
    delete[] p;
}
smink
+1  A: 

The best solution is to use new (std::nothrow) Type. This will act just like new Type, but will give null rather than throwing if it fails. This will be much easier than trying to make malloc behave like new.

If you really must use malloc, then remember to construct and destruct the object correctly:

void* memory = malloc(sizeof(Type));
Type* object = new (memory) Type;
object->~Type();
free(object); // or free(memory)

You can use this with a some smart pointers by giving it a custom deleter:

void malloc_deleter(Type* object)
{
    object->~Type();
    free(object);
}

if (void* memory = malloc(sizeof(Type)))
{
    Type* object = new (memory) Type;
    std::shared_ptr<Type> ptr(object, malloc_deleter);
    DoStuff(ptr);
}

But this would be much simpler using non-throwing new:

if (Type* object = new (std::nothrow) Type)
{        
    std::shared_ptr<Type> ptr(object);
    DoStuff(ptr);
}
Mike Seymour
+1  A: 

I have a question.

What happens if "Type" is a type whose constructor can throw? In that case, one still needs to handle exceptions in a try/catch block.

So is it a good idea to abandon exception based approach?

I would say that one can use the Abstract Factory/Factory Method design pattern and have all the 'new's in relatively lesser set of files/namespaces/classes, rather than these being scattered all around the place. That may also help in restricting the use of try/catch block to a relatively lesser code.

Chubsdad