views:

79

answers:

5

Here is two variants. First:

int n = 42;

int* some_function(int* input)
{
    int* result = new int[n];
    // some code
    return result;
}

int main()
{
    int* input = new int[n];
    int* output = some_function(input);

    delete[] input;
    delete[] output;
    return 0;
}

Here the function returns the memory, allocated inside the function.

Second variant:

int n = 42;

void some_function(int* input, int* output)
{
    // some code
}

int main()
{
    int* input = new int[n];
    int* output = new int[n];
    some_function(input, output);

    delete[] input;
    delete[] output;
    return 0;
}

Here the memory is allocated outside the function.

Now I use the first variant. But I know that many built-in c++ functions use the second variant. The first variant is more comfortable (in my opinion). But the second one also has some advantages (you allocate and delete memory in the same block).

Maybe it's a silly question but what variant is better and why?

+3  A: 

I think second variant is better, because you have "balanced responsibility over pointer". That makes code more readable, because you see where you allocate and where you free your memory.
If you want to use first variant, I'd suggest you to make dual funnction some_function_free(). As for malloc/free, new/delete, new[]/delete[], etc. Even that it will do simple delete[], by using this you'll save time when you'll want to change the way you allocate memory.

ony
+1  A: 

Generally speaking, it's better for functions not to heap-allocate and return objects, if practicable. It creates ownership issues, and complicates the interface (the caller has to know how to manage the lifespan of the returned object). It also puts more pressure on the memory allocator, which can in turn create thread contention, and denies the caller the opportunity to avoid this cost by allocating space for things more judiciously.

Marcelo Cantos
+6  A: 

Third variant

const int n = 42; 

template<class It1, class It2>
void some_function(It1 First, It1 Last, It2 output) 
{ 
    // some code 
} 

void main() 
{ 
    std::vector<int> input(n);
    std::vector<int> output(n);
    some_function(input.begin(), input.end(), output.begin()); 

} 
Alexey Malistov
+3  A: 

Neither variant is preferred C++ style, especially in the presence of exceptions. If an exception is thrown somewhere (either in the allocation of output or in the body of some_function) one or both of your dynamically allocated arrays will leak memory. The preferred way is to use the Resource Allocation Is Initialization (RAII) concept. Safe C++ code uses objects to acquire resources. Their destructors free those resources. As the stack unwinds from an exception, any resources acquired to that point are safely released.

In the case of dynamically allocated arrays, that means std::vector. If it doesn't adversely affect your performance (profile it if you're worried), you can even return one by value.

// don't need the global variable anymore
std::vector<int> some_function(std::vector<int> &input)
{
    std::vector<int> result;
    // do something
    return result;
}

int main()  // main returns int, not void
{
    std::vector<int> input;
    // insert some values
    std::vector<int> output = some_function(input);
    return 0;
}

No more need to worry about who is responsible for allocating and freeing memory. Your code becomes clearer and exception-safe.

Kristo
A: 

There's another benefit to the second one in that it does not require heap allocation. You can call the code using stack allocated memory only:

int main()
{
    int input[10];
    int output[10];

    some_function(input, output);
}
R Samuel Klatchko