Sunday 19 November 2017

c++ - In what cases do I use malloc and/or new?

Dynamic allocation is only required when the life-time of
the object should be different than the scope it gets created in (This holds as well for
making the scope smaller as larger) and you have a specific reason where storing it by
value doesn't work.


For
example:


 std::vector
*createVector(); // Bad
std::vector createVector(); //
Good
auto v = new std::vector(); // Bad
auto result =
calculate(/*optional output = */ v);
auto v = std::vector(); //
Good
auto result = calculate(/*optional output = */
&v);

From C++11 on, we have
std::unique_ptr for dealing with allocated memory, which
contains the ownership of the allocated memory. std::shared_ptr
was created for when you have to share ownership. (you'll need this less than you would
expect in a good program)


Creating an instance becomes
really easy:


auto instance =
std::make_unique(/*args*/); // C++14
auto instance =
std::make_unique(new Class(/*args*/)); // C++11
auto instance =
std::make_unique(42); // C++14
auto instance =
std::make_unique(new Class[](42)); //
C++11

C++17 also adds
std::optional which can prevent you from requiring memory
allocations


auto optInstance =
std::optional{};
if (condition)
optInstance =
Class{};

As soon as 'instance'
goes out of scope, the memory gets cleaned up. Transferring ownership is also
easy:


 auto vector =
std::vector>{};
auto instance =
std::make_unique();
vector.push_back(std::move(instance)); //
std::move -> transfer (most of the
time)

So when do you still need
new? Almost never from C++11 on. Most of the you use
std::make_unique until you get to a point where you hit an API
that transfers ownership via raw pointers.



auto instance = std::make_unique();

legacyFunction(instance.release()); // Ownership being transferred
auto
instance = std::unique_ptr{legacyFunction()}; // Ownership being captured
in unique_ptr

In C++98/03, you
have to do manual memory management. If you are in this case, try upgrading to a more
recent version of the standard. If you are
stuck:


 auto instance = new Class(); //
Allocate memory
delete instance; // Deallocate
auto instances =
new Class[42](); // Allocate memory
delete[] instances; //
Deallocate

Make sure that you
track the ownership correctly to not have any memory leaks! Move semantics don't work
yet either.


So, when do we need malloc in C++? The only
valid reason would be to allocate memory and initialize it later via placement
new.


 auto instanceBlob =
std::malloc(sizeof(Class)); // Allocate memory
auto instance =
new(instanceBlob)Class{}; // Initialize via constructor
instance.~Class(); //
Destroy via destructor
std::free(instanceBlob); // Deallocate the
memory

Even though, the above is
valid, this can be done via a new-operator as well. std::vector
is a good example for this.


Finally, we still have the
elephant in the room: C. If you have to work with a C-library
where memory gets allocated in the C++ code and freed in the C code (or the other way
around), you are forced to use malloc/free.


If you are in
this case, forget about virtual functions, member functions, classes ... Only structs
with PODs in it are allowed.


Some exceptions to the
rules:



  • You are writing a standard
    library with advanced data structures where malloc is
    appropriate

  • You have to allocate big amounts of memory
    (In memory copy of a 10GB file?)

  • You have tooling
    preventing you to use certain constructs

  • You need to
    store an incomplete type

No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...