Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The combination of manual memory management and exceptions is particularly nasty.

When you can't count on a GC to clean up for you every function has to be carefully coded to prevent potential leaks. Browse through some of Herb Sutter's GOTW questions to get an idea of exactly how tricky this can be.



Idiomatic C++ does not rely on manual memory management—it relies on deterministic memory management. Use unique_ptr, or shared_ptr when it makes sense (hint: it rarely does).


In theory you have every single leakable resource wrapped up in a RAII container or a smart pointer. In reality you're almost always dealing with raw pointers coming from a lower level C API or old C++ code or some kind of object handle you haven't wrapped yet.

Of course the recommendation from Stroustrup & Sutter is to use the new smart pointers for everything but I think it will be a few years at least before most people can follow that advice.


Typically what I do in that situation is lightly wrap the API. For instance:

    Image* image = allocate_image(…);
    …
    deallocate_image(image);

    ↓

    struct ImageDeleter {
        void operator()(void* image) const {
            deallocate_image(image);
        }
    };

    unique_ptr<Image, ImageDeleter> image(allocate_image(…));
That certainly can’t work everywhere, but I have yet to be failed by it.


You can reduce verbosity of the code by passing destructor function directly to unique_ptr constructor:

    std::unique_ptr<Image, void (*)(Image *)>(image, deallocate_image);


Cool, thanks for the tip. I meant to offer an example for the general case.


People who don't do this are just asking for it.


That's a lot of boilerplate code. Okay there are macros to wrap such things, but I guess it's things like this that would make the future reader of the code puzzled.


jmq & basman provide examples of how to do it succinctly.


Or, perhaps easier:

scoped_ptr<Image> image(allocate_image(...));


Sure. And using deep-thrown (i.e. thrown across module/library boundaries -- often exceptions are local tricks used within tightly coupled code) exceptions in an application where you're dealing with such pointers would be bad design.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: