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

前端 未结 19 1648
北恋
北恋 2020-11-21 17:41

I see in C++ there are multiple ways to allocate and free data and I understand that when you call malloc you should call free and when you use the

19条回答
  •  醉酒成梦
    2020-11-21 17:57

    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

提交回复
热议问题