Explain the 10 differences between new and malloc

Reprinted from: https://www.cnblogs.com/QG-whz/p/5140930.html

Preface

A few weeks ago I went to interview for an internship in C++ R&D. The interviewer asked a question:

What is the difference between new and malloc?

This is a commonplace question. At that time, I replied that new allocates memory from the free storage area, and malloc allocates memory from the heap; new/delete will call the constructor/destructor to initialize and destroy the object; operator new/delete can be overloaded; then forced analysis Let's look at the difference between free storage area and heap. After I came back, I felt that this question was actually not answered very well, because there are actually many differences between new and malloc. During the interview, it happened to be just after the final exam, and then there was no time to organize a few courses. Today, I spent some time sorting out this question.

10 differences between new and malloc

1. The location of the requested memory

new operator from the free store (free store) to dynamically allocate memory space for the object, the malloc function from the stack dynamically allocate memory. The free storage area is an abstract concept of C++ based on the new operator. Any memory application through the new operator is the free storage area. The heap is a term in the operating system. It is a special memory maintained by the operating system for the dynamic allocation of program memory. The C language uses malloc to allocate memory from the heap and free to release the allocated corresponding memory.

Then whether the free storage area can be a heap (the question is equivalent to whether new can dynamically allocate memory on the heap) depends on the implementation details of operator new. The free storage area can be not only a heap, but also a static storage area. It all depends on where operator new allocates memory for the object.

In particular, new may not even allocate memory for the object! The function of positioning new can do this:

new (place_address) type

place_address is a pointer that represents the address of a piece of memory. When using the above type to call the new operator with only one address, the new operator calls the special operator new, which is the following version:

void * operator new (size_t,void *) //不允许重定义这个版本的operator new

This operator new does not allocate any memory , it simply returns the pointer argument, and then the right new expression is responsible for the initialization of the object at the address specified by place_address.

2. Return type safety

When the memory allocation of the new operator succeeds, it returns a pointer of the object type. The type is strictly matched with the object, and no type conversion is required. Therefore, new is an operator that conforms to type safety . While malloc memory allocation is successful, it returns void *, and the void* pointer needs to be converted to the type we need through forced type conversion.
Type safety can be largely equivalent to memory safety. Type-safe code will not try to access memory areas where it is not authorized. A lot can be said about the type safety of C++.

3. The return value when memory allocation fails

When new memory allocation fails, bac_alloc exception will be thrown, it will not return NULL ; malloc returns NULL when memory allocation fails.
When using the C language, we are used to judging whether the allocation is successful after malloc allocates memory:

int *a  = (int *)malloc ( sizeof (int ));
if(NULL == a)
{
    ...
}
else 
{
    ...
}

Newcomers from the C language to the C++ camp may bring this habit into C++:

int * a = new int();
if(NULL == a)
{
    ...
}
else
{   
    ...
}

In fact , there is no point in doing this , because new does not return NULL at all, and the program can execute until the if statement has shown that the memory allocation is successful, and if it fails, an exception will be thrown. The correct approach should be to use the exception mechanism:

try
{
    int *a = new int();
}
catch (bad_alloc)
{
    ...
}

If you want to understand the basics of exceptions by the way, you can see http://www.cnblogs.com/QG-whz/p/5136883.html C++ exception mechanism analysis.

4. Do you need to specify the memory size

When using the new operator to apply for memory allocation, there is no need to specify the size of the memory block. The compiler will calculate it based on the type information, and malloc needs to explicitly indicate the size of the required memory.

class A{...}
A * ptr = new A;
A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A); 

Of course, it is not suitable for me to use malloc to allocate memory for our custom type. Please see the next one.

5. Whether to call the constructor/destructor

There are three steps when using the new operator to allocate object memory:

  • The first step: call the operator new function (operator new[] for arrays) to allocate a large enough, primitive , unnamed memory space to store a specific type of object.
  • The second step: The compiler runs the corresponding constructor to construct the object and passes in the initial value for it.
  • The third part: After the object is constructed, a pointer to the object is returned.

There are two steps when using the delete operator to release the memory of an object:

  • The first step: call the destructor of the object.
  • Step 2: The compiler calls the operator delete (or operator delete[]) function to release the memory space.

In short, new/delete will call the object's constructor/destructor to complete the object's construction/destructor. Malloc does not. If you are not too long-winded, you can take a look at my example:

class A
{
public:
	A() :a(1), b(1.11){}
private:
	int a;
	double b;
};
int main()
{
	A * ptr = (A*)malloc(sizeof(A));
	return 0;
}

Set a breakpoint at return and watch the contents of the memory pointed to by ptr:

It can be seen that the default constructor of A has not been called, because the values ​​of the data members a and b have not been initialized. This is why I said that using malloc/free to deal with C++ custom types is not appropriate, in fact, it is more than custom Types, all types in the standard library that need to be constructed/destructed are all inappropriate.

When using new to allocate objects:

int main()
{
    A * ptr = new A;
}

Looking at the assembly code generated by the program, it can be found that the default constructor of A has been called:

6. Processing of arrays

C++ provides new[] and delete[] to deal with array types:

	A * ptr = new A[10];//分配10个A对象

The memory allocated using new[] must be released using delete[]:

    delete [] ptr;

New's support for arrays is reflected in that it will call the constructor function to initialize each array element, and call the destructor for each object when the object is released. Note that delete[] should be used in conjunction with new[], otherwise it will find out the partial release of the array object and cause memory leaks.

As for malloc, it doesn't know the array you want to put in this memory or something else, anyway, it will give you a piece of original memory, and it will be done after giving you the address of the memory. So if we want to dynamically allocate the memory of an array, we also need to manually customize the size of the array:

int * ptr = (int *) malloc( sizeof(int)* 10 );//分配一个10个int元素的数组

7. Can new and malloc call each other

The implementation of operator new /operator delete can be based on malloc, and the implementation of malloc cannot call new. The following is a simple way to write operator new /operator delete, and other versions are similar:

void * operator new (sieze_t size)
{
    if(void * mem = malloc(size)
        return mem;
    else
        throw bad_alloc();
}
void operator delete(void *mem) noexcept
{
    free(mem);
}

8. Can it be overloaded

opeartor new /operator delete can be overloaded. The standard library defines 8 overloaded versions of the operator new function and the operator delete function:

//这些版本可能抛出异常
void * operator new(size_t);
void * operator new[](size_t);
void * operator delete (void * )noexcept;
void * operator delete[](void *0)noexcept;
//这些版本承诺不抛出异常
void * operator new(size_t ,nothrow_t&) noexcept;
void * operator new[](size_t, nothrow_t& );
void * operator delete (void *,nothrow_t& )noexcept;
void * operator delete[](void *0,nothrow_t& )noexcept;

We can customize any of the above function versions, provided that the customized version must be in the global scope or the class scope. Things that are too detailed are not described here. In short, we know that we have enough freedom to overload operator new /operator delete to determine how our new and delete allocate memory for objects and how to reclaim objects.

And malloc/free does not allow overloading .

9. Ability to reallocate memory intuitively

After using the memory allocated by malloc, if you find that the memory is insufficient during use, you can use the realloc function to re-allocate the memory to achieve memory expansion. realloc first judges whether the memory pointed to by the current pointer has enough contiguous space, if so, expand the allocatable memory address in place, and return the original address pointer; if the space is not enough, first allocate space according to the newly specified size, and change the original Data is copied from beginning to end to the newly allocated memory area, and then the original memory area is released.

new does not have such intuitive supporting facilities to expand memory.

10. The client handles insufficient memory allocation

Before operator new throws an exception to reflect an unsatisfied requirement, it will first call a user-specified error handling function, which is new-handler . new_handler is a pointer type:

namespace std
{
    typedef void (*new_handler)();
}

It points to a function with no parameters and no return value, which is an error handling function. In order to specify the error handling function, the client needs to call set_new_handler, which is a standard library function declared in:

namespace std
{
    new_handler set_new_handler(new_handler p ) throw();
}

The parameter of set_new_handler is the new_handler pointer, which points to the function to be called when operator new cannot allocate enough memory. The return value is also a pointer, pointing to the new_handler function that is being executed (but will be replaced soon) before set_new_handler is called.

For malloc, the client cannot programmatically decide what to do when the memory is not enough to allocate, and can only watch malloc return NULL.

to sum up

Organize the 10 differences mentioned above into a table:

feature new/delete malloc/free
Where to allocate memory Free storage area heap
Return value of memory allocation success Full type pointer void*
Return value of memory allocation failure Throw exception by default Return NULL
The size of the allocated memory Calculated by the compiler based on the type The number of bytes must be specified explicitly
Processing array There is a new version new[] that handles arrays The user needs to calculate the size of the array and then allocate the memory
Expansion of allocated memory Can't handle intuitively Simple to complete with realloc
Whether to call each other Yes, see the specific implementation of operator new/delete Cannot call new
Insufficient memory while allocating memory The customer can specify the processing function or reformulate the allocator Cannot be processed by user code
Function overloading allow Not allowed
Constructor and destructor transfer Don't call

What malloc gives you is like a piece of primitive land. What you want to grow needs to be planted on the land yourself

And new helps you draw up the fields (array), helps you plant seeds (constructor), and provides other facilities for you to use:

Of course, malloc is not to say that it is inferior to new, they have their own applications. In a language that emphasizes OOP such as C++, using new/delete is naturally more appropriate.

 

 

Guess you like

Origin blog.csdn.net/qq_44132777/article/details/114895308