-1

I come from the python world, were the memory management is taken care of. Having recently started writing some serious C++ code, I am curious about the memory allocation practices. I know that K&R suggest to use void functions to do any sort of big-array manipulation. While that is a perfectly valid way of getting things done, I prefer that my function returns are a little more descriptive.

Therefore, another solution is to have things like int * function (int param) {} that returns a memory block that has been malloced within the function. But there is no guarantee that whoever uses the function will free afterwards.

Here is the question then: "Is there a standard way to document memory-allocating functions?". In a way, I want to force the API user to free, based on my good faith that they will read the docs.

Maybe there are some other ways to enforce simple reference counting freeing?

Before taking any answers, I am looking for STL answers, since we would like to avoid Boost as long as possible.

Thanks all.

ivan-k
  • 811
  • 1
  • 7
  • 20

5 Answers5

2

I suggest having a look at some of the STL pointer classes, in particular std::auto_ptr (see comment below) and std::unique_ptr.

CompuChip
  • 9,143
  • 4
  • 24
  • 48
  • Note that there is probably no need to use pointers anyway. – juanchopanza Nov 06 '13 at 22:51
  • 1
    `std::auto_ptr` are pre-C11. `std::unique_ptr` are post-C11. Just a remark – ivan-k Nov 06 '13 at 22:58
  • Thanks @Manbroski, didn't know that. I'm not using C11 myself but it is good to keep this as a note. – CompuChip Nov 06 '13 at 23:03
  • @juanchopanza the question is not if there is a need for pointers, but _if_ you want to use them how you can make (at least reasonably, preferably completely) sure that the allocated memory is released. Returning reference-counted pointers such as `auto_ptr` instead of raw ones is one way to accomplish that - I am sure you could still break this but it would be hard to do without conscious effort. – CompuChip Nov 06 '13 at 23:04
  • 1
    No, not really. OP wants a memory block, and all they know is pointers. So they ask for a solution involving something like a pointer. It may well be that they really need this, but it could also be that they just need a vector, or something similar to a C++14 `std::dynarray`. – juanchopanza Nov 06 '13 at 23:07
  • 1
    The question is also about "big-array manipulation", and I suggest that the question about dynamic allocation and pointers is a red herring, because the OP incorrectly believes that if you want a dynamic array, that you have to use a pointer. But you don't have to use a pointer, smart or otherwise. Nor should you. The correct solution is almost certainly to use a vector. – Benjamin Lindley Nov 06 '13 at 23:09
2

If you need to return a dynamically sized array from a function (as the text in your question indicates you do), then the correct solution is a vector.

std::vector<int> function(int param)
{
    std::vector<int> v;
    ...
    return v;
}

There is no reason to involve pointers here, smart or otherwise.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • I like this approach... – juanchopanza Nov 06 '13 at 23:19
  • This is nice, but I am actually working with big multi-dimensional matrices. Their size is known in advance. Thank you for answering though, I like the approach as well. – ivan-k Nov 06 '13 at 23:25
  • 1
    @Manbroski a pointer doesn't do much good in representing a multi-dimensional matrix. Perhaps a refinement to this approach would be to write a matrix class that handles its own memory allocation (or uses a vector internally to do just that), and return one of those. – juanchopanza Nov 06 '13 at 23:28
  • 1
    @Manbroski: Okay, then the correct answer is to use a class which represents a multidimensional array, and return an object of that class *by value*. If you're unwilling to use an external library like boost, and you're unwilling to write that class, then your best bet is still a vector, *not* a pointer. – Benjamin Lindley Nov 06 '13 at 23:32
  • There are certain sparse matrix libraries that I am using, and those are done in pure C. So in my particular case, I have to use a pointer to properly communicate with them. I suppose I should have been more specific about the software stack in use. – ivan-k Nov 06 '13 at 23:53
1

Modern C++ offers several so called smart pointer classes to help with memory management. It should normally not be necessary to use malloc/free or even new/delete. The most important smart pointer classes, which are standardized since C++11, are:

To generate objects which are owned by a smart pointer, you should know about:


Smart!

Community
  • 1
  • 1
Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • How strange -- I virtually *never* use any of these smart pointers. – Jerry Coffin Nov 06 '13 at 23:27
  • ... when there is a good reason to use a smart pointer. – juanchopanza Nov 06 '13 at 23:31
  • @juanchopanza Sure, with containers and move-semantics there are a lot of cases where you don't need (smart) pointers and you should not use smart pointers when a pointer could be avoided. But if you need to handle pointers, you should use smart pointers - that's the point of my answer. – Daniel Frey Nov 06 '13 at 23:35
  • Sure, I get that, and I fully agree. I am just not entirely convinced OP wants a pointer, smart or not. – juanchopanza Nov 06 '13 at 23:35
1

A great deal here (almost everything, to be honest) depends on what you're really planning to do.

A few things are pretty easy though. First, you should almost never use malloc or free in C++. While there may be a few situations in which it's (arguably) reasonable to do so, they're unusual, and probably not something you should even consider until you really know what you're doing (at which time, you'll probably reject them, regardless of my advice). Likewise, you should avoid using raw pointers. Again, you might eventually encounter a situation where they're the best tool available, but for now (and the next year or two, at least) it's probably best to nearly forget that they exist at all.

Smart pointers are kind of a half-way point. While certainly a lot more acceptable than a raw pointer, they're still (at least in my opinion) less than desirable. Personally, I almost never use them either, though there are some pretty good C++ coders who use them a lot more than I do.

Some have already advised that you should typically work with something like an std::vector instead of using a pointer at all -- and I'd agree that this is good advice. I'd advise that you at least consider going a step further still: to the extent that it's at all reasonable, you should write your code as generic algorithms that work with iterators instead of working directly with a container.

For a simple example, let's consider an array of numbers, of which we want to find the arithmetic mean. Using raw memory, this might look something like:

double mean(double *data, size_t size) { 
   double total = 0.0;

   for (int i=0; i<size; i++)
      total += data[i];
   return total / size;
}

As pointer usage goes, that's fairly innocuous, but they're right that it can be cleaner if we use an std::vector:

double mean(std::vector const &v) { 
    double total = 0.0;

    for (int i=0; i<v.size(); i++)
       total += v[i];
    return total / v.size();
}

Using iterators with an algorithm for the standard library, we can simplify that a bit though:

template <class Iter>
double mean(Iter b, Iter e) {
    return std::accumulate(b, e, 0.0) / std::distance(b, e);
}

With this, we're no longer tied to one particular container type. For example, if we happen to have the numbers stored in a std::deque or std::list instead of a std::vector, this will still work just fine:

std::deque<double> numbers { 1.2, 3.4, 5.6, 7.8};

double average = mean(numbers.begin(), numbers.end());

std::list<double> more_numbers { 1.414, 1.732, 2.0 };

double another_average = mean(more_numbers.begin(), more_numbers.end());

This can also work for situations where we're producing multiple results, for which we need to allocate space. For example, if we took one collection of data as input, and produced another collection of data as output, we might call something like:

std::vector<something> results;

std::my_algorithm(input.begin(), input.end(), std::back_inserter(results));

In this case, the back_inserter returns an instance of a std::back_insert_iterator<T>, which will use the vector's push_back to insert results when we write to the iterator.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
-1

I suggest declaring your function with a reference to, for example a vector as parameter, which ensures that the vector exists and is allocated by caller. therefore caller will be responsible for lifetime of object where you will just fill it inside callee.

http://www.informit.com/articles/article.aspx?p=373338&seqNum=2

Hayri Uğur Koltuk
  • 2,970
  • 4
  • 31
  • 60
  • Then you have the problem of carefully documenting what exactly will happen to the passed vector, and the internal checks the function may need to do to it. If you need a function to give you a certain vector, the cleanest option is to return one. – juanchopanza Nov 06 '13 at 22:53
  • well if a function expects non-const reference, then i think obviously it will do something with that vector and if I call such a function, i think i would know what to expect (why would i call it otherwise). i'm not sure what you mean by internal checks though. anyway, thanks for your comment, i think especially given move semantics, your approach definitely is not worse than this – Hayri Uğur Koltuk Nov 06 '13 at 22:56
  • Well, what is the function supposed to to with the vector? Does it expect it to be empty? If not, should it clear it? If the function has to modify an existing vector, then yes, passing a reference expresses that intent clearly. Otherwise, it should be returning one. – juanchopanza Nov 06 '13 at 22:57
  • Actually there is merit to this approach. I would prefer doing this in C#, where you can use `ref` or `out` to indicate exactly what would happen with it; but if your function is named properly - e.g. "fillMatrixWithZeroes" instead of "createZeroMatrix" and it takes a pointer instead of a reference, it should be a pretty good hint to the caller that something is going on inside the function. The downside is that "a pretty good hint" is all you will get without R'ing TFM. – CompuChip Nov 06 '13 at 23:07