9

I am new to C++, coming from C#. Here is the code :

void function(int n)
{
    double* array = new double[n];

   //some work that can return or throw an exception
   //...

   delete[] array;
   return;
}

I know there is no C# using equivalent in C++.

Is there a simple and elegant way to ensure that memory will be released what ever happens ?

Sylvain B.
  • 719
  • 5
  • 31
  • 6
    Yes there is. Run a Google search on "smart pointers". – Sam Varshavchik Feb 01 '17 at 14:02
  • 6
    Or better yet [`std::array`](http://en.cppreference.com/w/cpp/container/array) (or possibly [`std::vector`](http://en.cppreference.com/w/cpp/container/vector)). – Some programmer dude Feb 01 '17 at 14:02
  • 4
    Read up on RAII idiom, used in Rust and C++. – Erik Alapää Feb 01 '17 at 14:08
  • @people who answered : sorry for the misleading example, the size of the array is not known at compile time – Sylvain B. Feb 01 '17 at 14:19
  • 7
    As a rule of thumb: If you are using `new` in C++ you are doing it wrong. – nwp Feb 01 '17 at 14:21
  • 2
    @nwp: As a side-note, since `new` did not exist prior to C++, your thumb-rule implies that there is something fundamentally wrong with this language to begin with. – barak manos Feb 01 '17 at 14:39
  • 1
    @barakmanos `new` is a very low level element. The difference between `new` and `malloc` is that `new` calls the constructor of the object. There's no way around it. It exists, because it's also used to build high-level stuff, like `vector` and `unique_ptr`, but honestly, using it when you can use high-level options is just stupid and arrogant. It's one of the worst things you can ever do! Unless you're doing kernel level programming or building something very specific, you shouldn't use `new`! Piece of advice: Don't ever say you use `new` everywhere in an interview, you'd never get that job! – The Quantum Physicist Feb 01 '17 at 14:51
  • @TheQuantumPhysicist it's even easier than "doing kernel level programming" - if you are writing `new` anywhere that isn't a class named *something*_ptr, you are doing it wrong – Caleth Feb 01 '17 at 15:07
  • 1
    @barakmanos your statement is logically unsound (or at least incomplete). The existence of a language construct which should not _generally_ be used does not in itself imply that there is anything fundamentally wrong with the language. (There's also room for argument about whether it was _always_ the case that use of `new` should generally be avoided). – davmac Feb 01 '17 at 15:10
  • @Caleth: ... or in a function `something_ptr make_something(Args...)` – MSalters Feb 01 '17 at 16:23

2 Answers2

13

In C++, the code would look as follows:

#include <vector>

void function()
{
    std::vector<double> array(100);

    //some work that can return when or throw an exception
    //...

    return;
}

If you really don't want to initialize the array elements and don't need to resize the array and don't need iterators, you can also use:

#include <memory>

void function()
{
    std::unique_ptr<double[]> array(new double[100]);

    //some work that can return when or throw an exception
    //...

    return;
}

In both cases you access the array elements with array[0], array[1], etc.

Finally, if you don't need to transfer ownership of the data out of the function, know the size of the array at compile time, and the size isn't too large, you may also consider having a direct array object:

void function()
{
    double array[100];  // uninitialized, add " = {}" to zero-initialize

    // or:

    std::array<double, 100> array;  // ditto

    //some work that can return when or throw an exception
    //...

    return;
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • `std::valarray` may also be useful depending on the specific problem being solved. – Andrew Feb 01 '17 at 14:42
  • I think it would be nice to mention `std::array` instead of raw arrays. – Guillaume Racicot Feb 01 '17 at 14:42
  • @GuillaumeRacicot: The size of `std::array` must be known at compile-time, and OP doesn't know the size until run-time (This was hidden in a comment on the OP: "@people who answered : sorry for the misleading example, the size of the array is not known at compile time") – AndyG Feb 01 '17 at 14:56
  • 2
    @AndyG So does the last example with the raw array; when you declare a raw array, the size must be known at compile-time. There is little to no reason to not change a raw array into `std::array` – Guillaume Racicot Feb 01 '17 at 14:58
  • 1
    @GuillaumeRacicot: I think Kerrek's answer was posted before OP's clarification. raw arrays definitely won't work, unless you elect to use the GCC extension. – AndyG Feb 01 '17 at 15:32
  • @AndyG: Good point, added `std::array` to the last example and clarified that the size needs to be know at compile time. – Kerrek SB Feb 01 '17 at 18:41
10

Automatic variables are destroyed automatically at the end of scope, whether due to return or a throw:

{
    double array[100];
    throw 1; // no memory leaked
}

sorry for the misleading example, the size of the array is not known at compile time

In that case you do need a dynamic array. A popular solution to handling cleanup of resources such as dynamic memory is to wrap the pointer (or handle or descriptor depending on the type of resource) in a class, that acquires the resource on initialization, and releases on destruction. Then you can create an automatic variable of this wrapper type. This pattern is called "Resource acquisition is initialization" or RAII for short.

You don't need to write your own RAII wrapper for a dynamic array however. The standard library has you covered: std::vector

eerorika
  • 232,697
  • 12
  • 197
  • 326