pluckyDuck
pluckyDuck

Reputation: 1159

Who is responsible for freeing allocated memory?

Consider the following code snippet

void xyz(CString **mapping)
{
    *mappings = new CString[10];
    (*mappings)[0] = "hello";
    //...
}

void main(int argc, char **argv)
{
    CString *tmp;
    xyz(&tmp);
    // now we have the CString array defined in xyz
}

What I'm trying to do is to fill a var from main with some values which are generated by another function. I read that its best practise to delete/free in the same function as it was allocated. This is not possible in this case because the only reason why xyz exists is to generate data (this is just an example, in real cases there would be some more complexity in xyz ;)). I also considered to create an array on the stack in main and pass it to the function but in my case the size of the array is not fix at that time (it is determined in xyz). What is the cleanest and most common way to clean up allocated memory? If we had an object with method xyz what would be best practice then? To create another method (for example freeMapping()) which has to be invoked by the caller after he processed the data?

Upvotes: 1

Views: 903

Answers (3)

bames53
bames53

Reputation: 88215

There are many different schemes that people have used over the years, some better or worse. Good strategies define a rigid and consistent pattern that establishes rules for 'ownership' of a resource, i.e. responsibility for cleaning up and ensuring nothing accesses the resource illegally. The rules of successful strategies are also such that only a local view of the resource and how it's used is necessary for safe access to the resource.

The strategy you should be using in modern C++ is called RAII or 'resource acquisition is initialization'. What that name means is that any resource that's acquired should be an initialization. For example:

std::string s = "Hello, World";

This code acquires some memory as a resource for storing the string data, but all you see is that the string is initialized. The object that is initialized owns the memory. That means it's responsible for managing the memory's lifetime and restricting access to it. Code using the object doesn't need to consider the resource at all. It only has to be sure it's using the object itself correctly, and the hidden resource's lifetime will be managed correctly in turn.

Using RAII is not only convenient for keeping normal management of a resource localized, it also greatly simplifies correctly cleaning up resources in the presence of exceptions. When a scope is exited due to an exception, C++ guarantees to destroy all completely constructed objects in that scope. If the necessary tasks for cleaning up resources is done by object destructors, then the resources will not leak, and there's no need to add explicit exception handling to every scope in which a resource is used.

C++ already includes resource owning classes for many types of resources. For a dynamically sized array use a std::vector:

std::vector<CString> xyz()
{
    // C++11
    return {"hello",...};

    // or C++03
    std::vector<CString> mappings;
    mappings.push_back("hello");
    ...
    return mappings
}

void main(int argc, char **argv)
{
    std::vector<CString> tmp = xyz();
    // now we have the CString array defined in xyz
    // the array gets automatically cleaned up by std::vector's destructor
}

Upvotes: 1

evarsanyi
evarsanyi

Reputation: 31

An RAII style class (a wrapper that frees the object in its dtor) is a common way to handle this sort of thing (see std::auto_ptr or some of the more modern alternatives such as boost::scoped_ptr or std::unique_ptr). When the auto_ptr/unique_ptr goes out of scope delete is called automatically.

Passing in a reference to a std::vector created on the callers stack may work.

Returning a std::vector by value is easy to understand and may perform quite well depending on your requirements.

Upvotes: 0

yozhik
yozhik

Reputation: 5074

It is bad practice that you show here. So it has 2 solutions:

  1. Allocate and free memory in main function.

  2. Make a class, which will be responsible for all operations with that string and use it in main function.

Upvotes: 0

Related Questions