Is it possible to put some restrictions in overloading operators new and delete?
My overloaded new is linked in a different file to my test program.
The scenario is:
if(condition is satisfied)
call overloaded new
else
call the actual new defined in new.h
Always use your overloaded new/delete and check your condition inside its implementation.
Once you replace the default ::operator new() you can't use it anymore - it's gone forever. See this question.
If you want to have the effect of the original ::operator new() you'll have to reimplement it which isn't very hard.
There are three ways to provide an operator new.
replacing one or more of the four non placement default operators new,
providing overload to the default operator new (thus with an additional parameter, those may be called with the placement new syntax),
providing operator new class members, those will be called only for that class and their descendant.
In the latter two cases, it is possible to call one of the more well know operators new with the syntax:
ptr = ::operator new(sz);
ptr = ::operator new[](sz);
ptr = ::operator new(sz, std::nothrow);
ptr = ::operator new[](sz, std::nothrow);
but if you have replaced them, your replacement will be called. You can't call the default operators new you have replaced (well perhaps you can by playing implementation specific linker tricks, but that's outside the scope of the language).
About the replacement of operator new:
you should replace the two operators new and the corresponding two operator delete together (or one of the delete operator could be easily called with unexpected pointer)
you should replace the two operators new[] and the corresponding two operator delete[] together (same reason)
pay attention to what is possible with the new handlers, some library plays with that.
You can easily perform the check in your overloaded new operator. Be sure to implement all flavours of the new operator (as AProgrammer already pointed out).
Calling the original/default new is not possible, but it's not difficult to implement it yourself. After all, new only allocates memory, that's it. So instead of calling the original/default new, you can also call malloc, HeapAlloc, or any memory-allocation routine found on your system. Be sure to call the corresponding memory-deallocation method (free, HeapFree, ...) in your implementation of delete.
You didn't tell what kind of condition you are going to check in your implementation of new? If it's a 'static' condition (I mean: always giving the same result during the execution of your application), the same condition should also be added to your implementation of delete.
If the condition depends on the situation and changes while running your application, you should foresee a method where you can know which delete implementation to use in your delete function. One trick do to this is the following:
In your implementation of new:
allocate 8 bytes more than requested (this must be 8 bytes to keep the alignment correct)
fill in the first 8 bytes with an identification so that you can know which underlying memory-allocation function you used
add 8 bytes to the allocated pointer and return this one
In your implementation of delete:
subtract 8 bytes of the pointer given to you
check the identification found at that place (see new) to see which kind of underlying delete-implementation you should call
Related
In a library I'm working on, I need to allocate space that will eventually be passed to placement-new to construct objects of arbitrary types. Those instances will be returned to the caller code, and need to behave properly with the user just writing delete t; or having whatever unique_ptr analog they're using do it for them.
The naive approach of T *t = new char[sizeof(T)] has at least a few problems that I've run noticed:
If T is declared with an alignas specifier, then I can't manually pad the buffer accordingly, because the resulting address won't be the right one to pass to delete
The expression delete t; will be a mismatch between operator delete() and operator delete[]()
If the code declares a custom T::operator new and T::operator delete (for memory pooling, segregation, tracking, whatever), then we neglect to call the allocator, and mis-match on the call to the de-allocator
Seemingly much better is T *t = std::allocator<T>::allocate(1), which addresses the alignment concern in point 1 and the scalar/array mismatch concern in point 2. However, per cppreference, it always calls the global ::operator new. Thus, it would still fail on point 3.
Is the reference wrong? Is there some slightly higher-level routine in the standard library I'm missing that does the right thing? Is there some trick to implementing the right thing correctly without nasty template code to check whether T::operator new exists?
I think you want to follow the same rules a new-expression uses to determine the correct allocation function to call, but I don't know any way off the top of my head to automatically produce that call. It's fairly straightforward in principle (I think) to write the usual family of templates to detect when the class-specific overloads are/are not present and branch of alignof(T) > __STDCPP_DEFAULT_NEW_ALIGNMENT__ but I agree it's tedious.
As we know, the C++ standard defines two forms of global allocation functions:
void* operator new(size_t);
void* operator new[](size_t);
And also, the draft C++ standard (18.6.1.2 n3797) says:
227) It is not the direct responsibility of operator
new or operator delete to note the repetition
count or element size of the array. Those operations are performed
elsewhere in the array new and delete expressions. The array new
expression, may, however, increase the size argument to operator
new to obtain space to store supplemental information.
What makes me confused is:
What if we remove void* operator new[](size_t); from the standard, and just use void* operator new(size_t) instead? What's the rationale to define a redundant global allocation function?
I think ::operator new[] may have been useful for fairly specialized systems where "big but few" arrays might be allocated by a different allocator than "small but numerous" objects. However, it's currently something of a relic.
operator new can reasonably expect that an object will be constructed at the exact address returned, but operator new[] cannot. The first bytes of the allocation block might be used for a size "cookie", the array might be sparsely initialized, etc. The distinction becomes more meaningful for member operator new, which may be specialized for its particular class.
In any case, ::operator new[] cannot be very essential, because std::vector (via std::allocator), which is currently the most popular way to obtain dynamic arrays, ignores it.
In modern C++, custom allocators are generally a better choice than customized operator new. Actually, new expressions should be avoided entirely in favor of container (or smart-pointer, etc) classes, which provide more exception safety.
::operator new[] and ~delete[] facilitate memory usage debugging, being a central point to audit allocation and deallocation operations; you can then ensure the array form is used for both or neither.
There are also lots of plausible if highly unusual/crude tuning uses:
allocate arrays from a separate pool, perhaps because that crucially improved average cache hits for small single-object dynamically-allocated objects,
different memory access hints (ala madvise) for array/non-array data
All that's a bit weird and outside the day-to-day concerns of 99.999% of programmers, but why prevent it being possible?
The standard (n3936) makes it clear that these two operators serve different but related purposes.
operator new calls the function void* operator new(std::size_t). The first argument must be identical to the argument to the operator. It returns a block of storage suitably aligned, and which may be somewhat larger than required.
operator new[] calls the function void* operator new[](std::size_t). The first argument may be larger than the argument supplied to the operator, to provide extra storage space if required for array indexing. The default implement for both is to simply call malloc().
The purpose of operator new[] is to support specialised array indexing, if available. It has nothing to do with memory pools or anything else. In a conforming implementation that made use of this feature, the implementation would set up specialised tables in the extra space and the compiler would generate code for instructions or calls to library library support routines that made use of those tables. C++ code using arrays and failing to use new[] would fail on those platforms.
I am not personally aware of any such implementation, but it resembles the kind of features required for the support of certain mainframes (CDC, IBM, etc) which have an architecture quite unlike the Intel or RISC chips we know and love.
In my opinion, the accepted answer is incorrect.
Just for completeness, the standard (n3936 mostly in S5.3.4) contains the following.
A distinction between allocating an 'array object' or a 'non-array object'
References to 'array allocation overhead', with the implication that extra storage might be needed and it might (somehow) be used for a repetition count or element size.
There is no reference to memory pools or any hint that this might be a consideration.
I'm sure there are proper use-cases out there that require separate new[] and new, but I haven't encountered one yet that is uniquely possible with this separation and nothing else.
However, I see it like this: since the user calls different versions of operator new, the C++ standard would have been guilty of wantonly and deliberately losing information if they'd defined just one operator new and had both new and new[] forward there. There is (literally) one bit of information here, that might be useful to somebody, and I don't think people on the committee could have thrown it out in good conscience!
Besides, having to implement the extra new[] is a very very minor inconvenience to the rest of us, if at all, so the trade off of preserving a single bit of information wins against having to implement a single simple function in a small fraction of our programs.
The C++ Programming Language: Special Edition p 423 says
_The operator new() and operator delete() functions allow a user to take over allocation and deallocation of individual objects; operator new[]() and operator delete[]() serve exactly the same role for the allocation and deallocation of arrays.
Thanks Tony D for correcting my misunderstanding of this nuance.
Wow, it's not often I'm caught out on something in C++ I'm so certain about - I must have been spending too much time in Objective-C!
original wrong answer
It's simple - the new[] form invokes the constructor on every element of a classic C array.
So it first allocates the space for all the objects, then iterates calling the constructor for each slot.
I am having hard time digesting this syntax:
void* operator new[](std::size_t, const std::nothrow_t&) throw();
while this is still understood:
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
Question:
I thought new and subscript [] are different operators. how can we combine two operators to overload in one definition?
Also the nowthrow. The following call doesnt make sense to me ( with respect to the signature of the function ).
int * p2 = new (nothrow) int;
If anyone can give reference to related topics from bjarne stroustrup's book that would be great, not a hard requirement though.
UPDATE: Please try to answer both questions :)
new[] and [] are two completely different operators.
new[] is an allocation operator for arrays, [] is a subscript access operator for arrays.
new[] is it's own operator, it's not simply 'new' allocator combined with '[]' subscript operator.
The first two are the signatures of the global new operators. For what (little) it's worth, operator new is used to allocate space for a new expression like x = new T;, while operator new[] is used to allocate space for a new expression like x = new T[count];. The "little" that it's worth is for a fairly simple reason: you should never use new T[count], so how it works is almost purely a historical curiosity.
You can overload ::operator new and/or ::operator new[] to provide your own heap allocation if you want to. There's no difference between the two as far as basic requirements go -- they both just allocate and return a pointer to the amount of memory requested.
As far as nothrow goes, the size that gets passed to operator new is always computed by the compiler based on the size of the object and in the case of an array new the count you give. Therefore, the parameter you specify in the new expression turns into the second parameter that's passed to operator new.
To emphasize a point I may not have made quite clearly enough above: operator new (and operator new[]) are used by, but separate from new expressions (what you have in your code when you say something like x = new T;). operator new and operator new[] are pretty much like malloc -- they just allocate "raw" memory. A new expression1 uses one of those to allocate raw memory, then invokes the constructor to allocate an object (or more than one, in the case of new T[count];) in that memory. The two are obviously related, but equally obviously not really the same.
One other minor point: it's also possible to have an operator new (or operator new[] as a class member. This allows you to allocate memory differently for that class than for others that use the global heap. This tends to be most common with small objects that you expect to allocate in large numbers. For these, the global heap often has quite a lot of overhead that you'd prefer to avoid.
Finally, when/if you want to allocate raw memory, you can also invoke operator new directly, as in void *a = ::operator new(1234);. About the only place this is common is if you decide to implement some sort of collection class on your own (e.g., if you want a circular buffer).
new and new[] are two separate operators, not really related to the '[]' operator.
This is best seen on the difference between delete p and delete[] p; are you deleting a single instance pointed to by p, or a whole array of instances?
Likewise, new[] is a way to allocate a whole array of objects, all in the same memory block.
What is the use of malloc and free when we have new and delete in C++. I guess function of both free and delete is same.
They're not the same. new calls the constructor, malloc just allocates the memory.
Also, it's undefined behavior mixing the two (i.e. using new with free and malloc with delete).
In C++, you're supposed to use new and delete, malloc and free are there for compatibility reasons with C.
In C++, it is rarely useful that one would use malloc & free instead of new& delete.
One Scenario I can think of is:
If you do not want to get your memory initialized by implicit constructor calls, and just need an assured memory allocation for placement new then it is perfectly fine to use malloc and free instead of new and delete.
On the other hand, it is important to know that mallocand new are not same!
Two important differences straight up are:
new guarantees callng of constructors of your class for initializing the class members while mallocdoes not, One would have to do an additional memset or related function calls post an malloc to initialize the allocated memory to do something meaningful.
A big advantage is that for new you do not need to check for NULL after every allocation, just enclosing exception handlers will do the job saving you redundant error checking unlike malloc.
First, when you speak of new and delete, I assume you mean the
expressions, and not the operator new and operator delete functions.
The new and delete expressions are not related to malloc and
free, and only manage memory incidentally; their main role is to
manage object lifetime: a new expression will call the operator new
function to obtain memory, and then call the constructor; a delete
expression will call the destructor before calling operator delete to
free the memory. For the most part, objects should be created, and
not simply allocated, which means using the expressions exclusively.
There are some rare cases where one wants to separate allocation and
initialization (creation); implementing things like std::vector is a
classical example, where you'll allocate for many objects in one go, but
only construct one at a time. In such cases, you'll use the operator
new function for allocation, and placement new for initialization; at
the other end, you'll explicitly call the constructor (something like
p->~T()) for destruction, and use the operator delete function to
free the memory.
Off hand, I can only think of two cases where you'd use malloc and
free in C++. The first is to implement your own replacements of the
::operator new and ::operator delete functions. (I often replace
the global ::operator new and ::operator delete with debugging
versions, which trace allocations, put guard zones around the allocated
memory, etc.) The other is when interacting with a legacy library
written in C: if the library says to pass a pointer to memory allocated
by malloc (because it will free it itself using free), or more
commonly, returns a pointer to memory allocated by malloc, which
you're expected to free, then you must use malloc and free. (The
better libraries will provide their own allocation and deallocation
functions, which do more or less what the new and delete operators
do, but there will always be things like strdup().)
Is there a difference between:
operator delete(some_pointer);
and
delete some_pointer;
and if so what is the difference and where one should use one and where the other version of this operator?
Thanks.
Ironically, the delete operator and operator delete() are not the same thing.
delete some_pointer; calls the destructor of the object pointed to by some_pointer, and then calls operator delete() to free the memory.
You do not normally call operator delete() directly, because if you do, the object's destructor will not be called, and you are likely to end up with memory leaks.
The only time you have to care about operator delete() is when you want to do your own memory management by overriding operator new() and operator delete().
To top it off, you should also be aware that delete and delete [] are two different things.
operator delete() simply frees the memory. delete some_pointer calls some_pointer's destructor, and then calls operator delete().
delete some_pointer; is the "correct" one to use.
operator delete(some_Pointer); exist mainly as an artifact of the syntax for defining you own delete operator. That is, because you define an plus operator as;
myclass::operator+(myclass b) {....}
you really could write:
myclass c = a.operator+(b);
but no one ever does that. They use:
myclass c = a + b;
Similarly, you could write operator delete(some_Pointer);, but no one ever does.
At least in my experience, it's more common to implement operator new and operator delete than to actually use (i.e., call) them, at least directly.
Usually, you use operator new and operator delete indirectly -- you write a new expression, like A *a = new A;. To implement this, the compiler generates code that invokes operator new to allocate raw memory, then invokes a A::A to convert that raw memory into an A object, much as if you'd written:
void *temp = operator new(sizeof A); // allocate raw memory with operator new
A *a = new(temp) A; // convert raw memory to object with placement new
When you're done with the object, you use delete A;. To implement that, the compiler invokes the dtor for the object, and then frees the memory, roughly like you'd done:
a->~A();
operator delete(a);
There are also operator [] new and operator [] delete, which are used when/if you allocate/delete arrays -- but there isn't necessarily any real difference between the normal version and the array version -- they both just allocate a specified amount of raw memory (though you might guess that the array versions will allocate relatively large amounts of memory, and do some optimization on that basis).
In any case, if you want to optimize how memory is allocated for objects of a particular class you overload these to do it. There are a fair number of existing implementations that you can drop-in and use, especially for situations where you expect to allocate a large number of tiny objects so you need to minimize the overhead associated with each allocation (e.g., HeapLayers, Loki's small block allocator).
One interesting little tidbit: operator new, operator [] new, operator delete and operator [] deleteare alwaysstaticclass members, even if you don't explicitly includestatic` in their declaration/definition.
There are also global versions of all four (::operator new, ::operator [] new, ::operator delete and ::operator [] delete). These mark the "border" between the "internal" C++ memory management, and the outside world. Typically they allocate relatively large chunks of memory from the operating system, and then return smaller pieces to the rest of the program upon request. If you want to (try to) optimize memory management for your entire program, you typically do it by overloading (or, really, replacing) these. Again, the typical reason would be if you expect to allocate a lot of small objects (but not in just a few classes). One example of this is the Boost Pool library.
Direct use of any of the above is generally restricted to situations where you need a block of raw memory, not objects. One example would be implementing your own container classes. For example, std::vector normally uses ::operator new (via an Allocator object) to allocate memory in which to store objects. Since it needs to be able to allocate storage, but only later (or perhaps never) create objects in that storage, it can't just use something like data = new T[size]; -- it has to allocate raw memory, then use placement new to create objects in the memory as you add them to the collection (e.g., when you push_back an object). The same is true with std::deque. If you wanted (for example) to implement your own circular buffer "from the ground up", handling all the memory management directly instead of using something like vector for storage, you'd probably need/want to do the same.