Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

New and delete operators override in libraries

What happens if two libraries (dynamicaly linked) have their own globally overridden version of the new and the delete operators and they use their own memory management?

Is it generally wrong to ship memory management facilities inside a library, or can it be good in some cases to provide memory management only for some specific classes, defining only class-specific new and delete operators override?

Are there some differences in the case of static linked libraries?

like image 610
nyarlathotep108 Avatar asked Dec 11 '15 13:12

nyarlathotep108


People also ask

Can we overload new and delete operators?

New and Delete operators can be overloaded globally or they can be overloaded for specific classes. If these operators are overloaded using member function for a class, it means that these operators are overloaded only for that specific class.

What happens when we use new and delete operators?

Memory that is dynamically allocated using the new operator can be freed using the delete operator. The delete operator calls the operator delete function, which frees memory back to the available pool. Using the delete operator also causes the class destructor (if one exists) to be called.

What is difference between new and delete operator in C++?

The main difference between new and delete operator in C++ is that new is used to allocate memory for an object or an array while, delete is used to deallocate the memory allocated using the new operator. There are two types of memory as static and dynamic memory.

How new and delete operators are used to allocate and de allocated the memory for a pointer give examples?

Examples: delete p; delete q; To free the dynamically allocated array pointed by pointer-variable, use the following form of delete: // Release block of memory // pointed by pointer-variable delete[] pointer-variable; Example: // It will free the entire array // pointed by p.


2 Answers

In general, this is labelled "here be dragons". It depends on all sorts of things. Often the two libraries will fight, and new and delete will end up overridden by one of them - that's the best you can hope for.

Alternatives:

  • Library A starts up. Overrides new/delete, allocates some memory. Library B starts up and overrides. At system shutdown, library A's memory is freed with library B's delete. That is not good.

  • Memory allocated in library A uses library A's override, and similarly for library B. If you ever end up with memory allocated in library A being freed by library B, you will lose. (And it can be even more confusing, because if the object being deleted by B has a virtual destructor, the deletion can end up being done by A ... so it works.)

like image 172
Martin Bonner supports Monica Avatar answered Oct 16 '22 08:10

Martin Bonner supports Monica


I think Martin pretty well answers your question, by outlining what happens and also nothing that it's a bit dangerous and not highly advisable (there be dragons indeed). Let me extend it a bit by providing an alternative: avoid overriding new/delete, and instead use the allocator concept.

For instance, if you look at std::vector, you notice that it is templated both on what type it stores, but also on an allocator. By writing a conforming allocator, you can control exactly how std::vector allocates and de-allocates memory. Notice how nice and loosely coupled this is: you have no difficulty exerting full control over memory allocation even though you can't change any of the original std::vector source code.

If you want library B to do allocation in a specific way, what I would do is:

  1. Write an allocator that conforms to the allocator concept in the way that std::allocator does.
  2. Make sure that all classes that use dynamic memory allocation directly (e.g. not through one of their members) are allocator aware.
  3. Typedef all of those classes so that they use your allocator by default.

To clarify step 3, what I mean is write something like this in a fundamental header file of your library:

template <class T>
using my_lib::vector = std::vector<T, my_lib::MyAllocator<T>>;

Now you can use ''vector'' anywhere in your library, which will be a normal vector but using your allocation scheme.

Step 1 can range from very easy (for stateless allocators) to quite tricky (there's a number of gotcha with stateful allocators). As for step 2, it's quite straightforward as far as dynamic memory for containers goes as all of the containers in the standard library already support this. But if you are using dynamic memory for e.g. polymorphism, you'll need to do a bit of extra work (probably write a suitable wrapper) to do this in an allocator-aware way.

If someone has good examples of reasons why you'd want to override new/delete as opposed to using allocators (e.g. because there is something you can't do with allocators) I'd be interested to hear them.

Edit: and just to bring this full circle, note that there will not be any problem using libraries A and B simultaneously if you do this, as no global operators have been overridden.

like image 8
Nir Friedman Avatar answered Oct 16 '22 09:10

Nir Friedman