开发者

Freeing memory in caller or callee?

开发者 https://www.devze.com 2023-04-12 06:24 出处:网络
A function (Say \"fun()\") allocates memory and return开发者_开发技巧s the pointer to allocated memory.

A function (Say "fun()") allocates memory and return开发者_开发技巧s the pointer to allocated memory. How should I make sure I that this memory is released. I can't release it immediately in function "fun()" as it is returned to caller. And what if fun() is part of library? Whose responsibility it is to free memory. In case of fopen(), the memory is released by fclose(). But in my case, "fun()" is called repeatedly. So I can not wait till end to release the memory.


The following is the answer for C, posted before the OP confessed to using C++. In that language, use RAII and smart pointers, as recommended by others.

If a function returns allocated memory, then the caller is responsible for deallocation and this must be stated in the function's documentation.

If more cleanup is needed then is offered by free, or such cleanup may to be needed in future versions of the library, then you should offer a cleanup function (like stdio does with fclose) that does the deallocation. If you can't predict whether extra cleanup may be necessary in the future, then it's a good idea to assume it will be at some point. Wrapping free is cheap.

Think of it as a form of symmetry: if the client gets a resource (object) from the library, then it is eventually responsible for handing it back to the library for disposal:

void use_the_foo_library()
{
    Foo *f = make_foo();
    if (f == NULL)
        ERROR();

    foo_do_bar(f);
    foo_do_baz(f);

    foo_destroy(f);
}

where in foolib 1.0, foo_destroy is just

void foo_destroy(Foo *p)
{
    free(p);
}

but in version 2.0, it may have grown to

void foo_destroy(Foo *p)
{
    fclose(p->logfile);
    free(p);
}

etc. This style is consistent with the opaque pointer design pattern. It also gives you the freedom of replacing malloc and free at any point with a special purpose memory allocator, such as a pool allocator, without having to change any client code.


If it's C++, don't return a raw pointer to memory, return a smart pointer instead.

eg:

std::shared_ptr<TypePointedTo> data = fun();

That way, when the shared_ptr destructs it will automatically free the memory for you.

Or, if it's an array you want to return use a vector, again this will automatically free the memory for you:

std::vector<BYTE> data = fun();

Read the excellent comments, std::unique_ptr could be a better than std::shared_ptr in a lot of scenarios.

If it's C ... see other answers!


In C++, you would return a smart pointer, which clearly states (and enforces) that ownership has been transferred to the caller, and allows the caller to choose what to do with it. It also provides exception safety, preventing a memory leak if an exception (or just an early function return) causes the only pointer to the resource to go out of scope.

In C++03, std::auto_ptr is the best choice here; in C++11, this is deprecated in favour of std::unique_ptr.


C Solution:

And what if fun() is part of library?

Your library api should then doccument the fact memory needs to freed by the caller.
You also should provide a free function for the same and mandate that user of the library should call it to free the allocation.

EDIT:

C++ Solution:

Since you edited to say that you are using C++, perhaps it is best to use smart pointers (std::tr1::shared_ptr)to automatically handle the memory for you.

If you cannot use smart pointers for some reason using std::vector is also a good choice.


If you need the memory outside of the callee, it's pretty obvious that it is responsible to free up the memory, since you can't really free it in the callee. It's the same as new and delete - you simply must remember to free that memory. Make sure you document the fact that the caller is responsible for memory management.


You have to document that memory is allocated and that the caller is responsible for freeing it. You can't free it yourself as you can't know the caller's intention. you'd be freeing it before use.

You could provide a cleanUp() method to be called and flush the memory but that relies on the caller still and you add complications around when it should be called.

The only real alternative is to set up a clever "reference counting" mechanism such as in Objective-C (see release and autorelease).

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号