I have written a simple function as following:
void *operator new(size_t size) throw(std::bad_alloc)
{
void *p;
p = malloc(size);
if(!p)
throw bad_alloc();
return p;
}
What else can i do to improve this? Would malloc be more effective than new? If I want to write new[] do I only need to change just the function signature?
This code will work the way it is, but if you do this, you pretty much need to write a matching ::operator delete that will work with it:
void operator delete(void *block) throw() {
::free(block);
}
Personally, I'd probably modify your code to something more like:
void *operator new(size_t size) throw(std::bad_alloc)
{
void *p = malloc(size);
if(!p)
throw bad_alloc();
return p;
}
I prefer to initialize everything I can, rather than create an uninitialized variable, and only later assign a value to it. In this case, the difference is pretty minor, but I consider it a habit worth cultivating.
As far as being more effective than the default implementation of operator new, I'd say chances are that no, it won't be more effective, and might well be less effective. What you've provided is basically how many standard libraries were implemented toward the dawn of C++, but since then, many (most?) have done more work on their implementation of ::operator new to tailor it more closely to how dynamically allocated memory tends to be used in C++ (where malloc is mostly oriented toward how it's used in C, which is typically at least a little different).
As far as new[] goes, yes, it's just a change of function signature. Despite being used for single vs. multiple allocations, the requirements on operator new and operator new[]` are identical.
If you replace global operator new you also should replace the nothrow variant. And, of course, global operator delete (both the normal and nothrow variant, because if the constructor of the object throws, the nothrow variant of operator delete is called for nothrow operator new).
I guess in most implementations the built-in operator new looks more or less exactly like your replacement. Anyway, in general I'd not expect that you can beat the internal implementation of operator new.
operator new is responsible for allocating the underlying memory of an object. Some applications use other allocation schemes than malloc to allocate memory. One example is pool allocation: The application requests a large amount of memory from the operating system and manages how that memory itself. This can safe the overhead of a system call, prevent fragmentation or provide time guarantees for memory allocation that the operating system usually wont.
If you don't know if this could improve the performance of your program, it probably does not matter for you.
Related
Assuming I'm using a struct to be allocated on heap and used as
new [] and delete[]
shared_ptr(new [])
then can I simply overload its new array operator and don't touch any delete [] operator
struct alignas(256) MyStruct
{
Item i1,i2;
void * operator new[](unsigned long int size)
{
return aligned_alloc(256,size);
}
void * operator new (unsigned long int size)
{
return aligned_alloc(256,size);
}
};
and consider it done without any leaks?
GCC 6.3 and c++0x.
The truth is, there is no guarantee on how your standard library implements those operator new() functions, whatsoever. Your standard implementation might just call through to malloc() and free(), but it's not required to do so. It may just as well use the sbreak() syscall itself to back the memory objects it manages. Or it could use the mmap() syscall.
Either of these three is perfectly possible, and incompatible with the other two implementations. And, just as bad, your standard operator delete() implementation may consult some hidden data fields in front of the pointer that you pass into it to perform its internal bookkeeping. If the pointer that is passed into your standard operator delete() is not actually a pointer that was returned by the matching operator new(), you have undefined behavior. And the probability of something really bad happening is very high.
There is really no way around it: If you supply operator new(), you must also supply operator delete(). Otherwise, all hell may break loose.
If you overload new on a object, you should overload delete as well. Likewise, if you overload new[], you should overload delete[]. This is because the object will use the default delete, which may lead to a crash, depending on how you've messed with new.
Depending on your compiler, delete may call free() anyway, but you should get into the habit of overloading both new and delete, especially if you change how your object gets allocated.
In his new book TC++PL4, Stroustrup casts a slightly different light on a once usual practice regarding user-controlled memory allocation and placement new—or, more specifically, regarding the enigmatical "placement delete." In the book's sect. 11.2.4, Stroustrup writes:
The "placement delete" operators do nothing except possibly inform a garbage collector that the deleted pointer is no longer safely derived.
This implies that sound programming practice will follow an explicit call to a destructor by a call to placement delete.
Fair enough. However, is there no better syntax to call placement delete than the obscure
::operator delete(p);
The reason I ask is that Stroustrup's sect. 11.2.4 mentions no such odd syntax. Indeed, Stroustrup does not dwell on the matter; he mentions no syntax at all. I vaguely dislike the look of ::operator, which interjects the matter of namespace resolution into something that properly has nothing especially to do with namespaces. Does no more elegant syntax exist?
For reference, here is Stroustrup's quote in fuller context:
By default, operator new creates its object on the free store. What
if we wanted the object allocated elsewhere?... We can place objects
anywhere by providing an allocator function with extra arguments and
then supplying such extra arguments when using new:
void* operator new(size_t, void* p) { return p; }
void buf = reinterpret_cast<void*>(0xF00F);
X* p2 = new(buf) X;
Because of this usage, the new(buf) X syntax for supplying extra
arguments to operator new() is known as the placement syntax.
Note that every operator new() takes a size as its first argument
and that the size of the object allocated is implicitly supplied.
The operator new() used by the new operator is chosen by the
usual argument-matching rules; every operator new() has
a size_t as its first argument.
The "placement" operator new() is the simplest such allocator. It
is defined in the standard header <new>:
void* operator new (size_t, void* p) noexcept;
void* operator new[](size_t, void* p) noexcept;
void* operator delete (void* p, void*) noexcept; // if (p) make *p invalid
void* operator delete[](void* p, void*) noexcept;
The "placement delete" operators do nothing except possibly inform a
garbage collector that the deleted pointer is no longer safely
derived.
Stroustrup then continues to discuss the use of placement new with arenas. He does not seem to mention placement delete again.
If you don't want to use ::, you don't really have to. In fact, you generally shouldn't (don't want to).
You can provide replacements for ::operator new and ::operator delete (and the array variants, though you should never use them).
You can also, however, overload operator new and operator delete for a class (and yes, again, you can do the array variants, but still shouldn't ever use them).
Using something like void *x = ::operator new(some_size); forces the allocation to go directly to the global operator new instead of using a class specific one (if it exists). Generally, of course, you want to use the class specific one if it exists (and the global one if it doesn't). That's exactly what you get from using void *x = operator new(some_size); (i.e., no scope resolution operator).
As always, you need to ensure that your news and deletes match, so you should only use ::operator delete to delete the memory when/if you used ::operator new to allocate it. Most of the time you shouldn't use :: on either one.
The primary exception to that is when/if you're actually writing an operator new and operator delete for some class. These will typically call ::operator new to get a big chunk of memory, then divvy that up into object-sized pieces. To allocate that big chunk of memory, it typically (always?) has to explicitly specify ::operator new because otherwise it would end up calling itself to allocate it. Obviously, if it specifies ::operator new when it allocates the data, it also needs to specify ::operator delete to match.
First of all: No there isn't.
But what is the type of memory? Exactly, it doesn't have one. So why not just use the following:
typedef unsigned char byte;
byte *buffer = new byte[SIZE];
Object *obj1 = new (buffer) Object;
Object *obj2 = new (buffer + sizeof(Object)) Object;
...
obj1->~Object();
obj2->~Object();
delete[] buffer;
This way you don't have to worry about placement delete at all. Just wrap the whole thing in a class called Buffer and there you go.
EDIT
I thought about your question and tried a lot of things out but I found no occasion for what you call placement delete. When you take a look into the <new> header you'll see this function is empty. I'd say it's just there for the sake of completeness. Even when using templates you're able to call the destructor manually, you know?
class Buffer
{
private:
size_t size, pos;
byte *memory;
public:
Buffer(size_t size) : size(size), pos(0), memory(new byte[size]) {}
~Buffer()
{
delete[] memory;
}
template<class T>
T* create()
{
if(pos + sizeof(T) > size) return NULL;
T *obj = new (memory + pos) T;
pos += sizeof(T);
return obj;
}
template<class T>
void destroy(T *obj)
{
if(obj) obj->~T(); //no need for placement delete here
}
};
int main()
{
Buffer buffer(1024 * 1024);
HeavyA *aObj = buffer.create<HeavyA>();
HeavyB *bObj = buffer.create<HeavyB>();
if(aObj && bObj)
{
...
}
buffer.destroy(aObj);
buffer.destroy(bObj);
}
This class is just an arena (what Stroustrup calls it). You can use it when you have to allocate many objects and don't want the overhead of calling new everytime. IMHO this is the only use case for a placement new/delete.
This implies that sound programming practice will follow an explicit call to a destructor by a call to placement delete.
No it doesn't. IIUC Stroustrup does not mean placement delete is necessary to inform the garbage collector that memory is no longer in use, he means it doesn't do anything apart from that. All deallocation functions can tell a garbage colector memory is no longer used, but when using placement new to manage memory yourself, why would you want a garbage collector to fiddle with that memory anyway?
I vaguely dislike the look of ::operator, which interjects the matter of namespace resolution into something that properly has nothing especially to do with namespaces.
"Properly" it does have to do with namespaces, qualifying it to refer to the "global operator new" distinguishes it from any overloaded operator new for class types.
Does no more elegant syntax exist?
You probably don't ever want to call it. A placement delete operator will be called by the compiler if you use placement new and the constructor throws an exception. Since there is no memory to deallocate (because the pacement new didn't allocate any) all it does it potentially mark the memory as unused.
I have encountered the following code:
class a {
public:
void * operator new(size_t l, int nb);
double values;
};
void *a::operator new (size_t l,int n)
{
return new char[l+ (n>1 ? n - 1 : 0)*sizeof(double)];
}
From what I get it is then used to have an array like structure that start at "values":
double* Val = &(p->a->values) + fColumnNumber;
My question is :
is there a memory leak? I am very new to overloading new operator, but I'm pretty sure that the memory allocated is not deallocated properly. Also does that mean I can never create a "a" class on the stack?
thanks
I believe it technically produces UB as it is, though it's a form of UB that will probably never cause a visible side effect (it's using new [], but I believe that'll get matched up with delete -- but for char, this usually won't cause a visible problem).
IMO, it's almost worse that it's using a new expression to allocate what should really be raw bytes instead of objects. If I were doing it, I'd write it like:
void *a::operator new (size_t l,int n)
{
return ::operator new(l+ (n>1 ? n - 1 : 0)*sizeof(double));
}
You'd match that up with:
void a::operator delete(void *block)
{
::operator delete(block);
}
I don't see why the default operator delete called on an a * wouldn't be able to correctly deallocate the memory allocated by this custom operator new. The best way to check would be to actually write some code and find out, although rather than rob05c's technique I'd probably run it in a profiler such as valgrind. I assume the questioner sees a memory leak happening and suspects this as the cause, so writing a test case around this operator seems like a worthwhile endeavour.
Obviously it will leak if nobody gets around to actually deleting it afterwards...
I'd question the necessity of overriding new for this kind of functionality, but I also assume this was somebody else's code.
It's fairly easy to find out. Write a loop that constructs and deconstructs lots of a's, and watch your memory usage. It'll go up pretty fast if it's leaking.
Its fine as it is, but you'd need to use delete[], not delete, from the code that uses this class as it allocates an array. Note that the user wouldn't get any hints that they need to do this - so overloading a delete operator for them would be a good idea.
You can definitely create Class "a" on the stack.
There are 4 (actually more but will stick with the basics) new & delete method signatures you should know.
void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new[] (std::size_t size) throw (std::bad_alloc);
void operator delete (void* ptr) throw ();
void operator delete[] (void* ptr) throw ();
You are allocating an array within the "operator new" method which should be done in the "operator new[]" method. This will get rid of your nasty check. Write both, "operator new" and "operator new[]"
Don't forget you want to give the caller an object of type "a" ( a myA = new a) so make sure you return "a" not char*, therefore you need to also be casting.
You need to write the corresponding delete[] and delete methods.
To answer your question, I believe it does leak memory. The new signature you've provided is called the "placement new". This allows you to allocate a new pointer without allocating memory but to give it a location to point to. Example: If you needed a pointer to a specific point in memory.
long z = 0x0F9877F80078;
a myA = new (z) a[5]; // 5 pointers that point to 0x0F9877F80078
By definition the placement-new operator is not supposed to allocate memory and since you have you make be leaking. Get rid of your second argument, which you can do now since you have 2 versions of operator new and you're good to go. Don't forget to return an object "a".
Check out IBM's Info Center:
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr318.htm
And the reference or references, cpluplus.com:
http://www.cplusplus.com/reference/std/new
I was wonder how malloc would allocate memory (can you tell me ?), so I tried something.
Is this a bad way to allocate memory ?
void* myMalloc(unsigned int size) {
return (void*) new bool[size];
}
The C++ standard states explicitely that the C malloc and free functions must not call operator new or operator delete (20.6.13/3 and 4 in the C++11 FDIS). This makes a red light blink in my mind...
Aside from that, your approach dumps all type-safety new could give you that malloc lacks. And your implementation will be too slow for what it does.
Conclusion: yes, this is a bad way to allocate memory.
The are some mistakes:
1) you're assuming sizeof(bool) == 1, which is not necessarily true. Change the
return (void*) new bool[size];
to
return (void*) new char[size];
2) how will you free the memory? You'd have to do something like:
char* x = myMalloc(unsigned int size);
delete[] x; //not free, since you actually use new and not malloc
3) malloc doesn't call new, it's probably the other way around (in VS20xx new will call malloc). malloc also doesn't call the constructors, so if this does work, it will only work for basic types.
I hate to disagree with quite so many people recommending that you use new char[n], but I feel obliged to do so.
Since you want to allocate "raw" memory, not objects, you should really use ::operator new instead of new some_type[some_size]:
void *myMalloc(size_t size) {
return ::operator new(size);
}
Ultimately, new char[whatever] isn't particularly harmful, but (at least IMO) it's conceptually wrong, and I see no advantage over using ::operator new directly.
malloc()/free() is not necessarily compatible with new and delete. new might very well invoke malloc() (at least by default), but you shouldn't count on it.
One major difference between malloc() and new() is that malloc() returns a void* that points to raw memory, whereas new returns a typed pointer and calls the constructor, if any (and delete calls the destructor).
If you're writing C++, there is very rarely a good reason to allocate raw untyped memory.
But if you really want to do so, you can write something like:
void *p = (void*)new char[size];
If you want to allocate a certain number of bytes with new[], use new char[n]. Unlike bool, sizeof(char) is guaranteed to be 1.
As to implementation of new and malloc, new is a higher-level construct (as it also calls constructors for types that have those), and therefore likely implemented in terms of malloc, not the other way round.
This question already has answers here:
What is the difference between new/delete and malloc/free?
(15 answers)
Closed 1 year ago.
I know how they are different syntactically, and that C++ uses new, and C uses malloc. But how do they work, in a high-level explanation?
See What is the difference between new/delete and malloc/free?
I'm just going to direct you to this answer: What is the difference between new/delete and malloc/free? . Martin provided an excellent overview. Quick overview on how they work (without diving into how you could overload them as member functions):
new-expression and allocation
The code contains a new-expression supplying the type-id.
The compiler will look into whether the type overloads the operator new with an allocation function.
If it finds an overload of an operator new allocation function, that one is called using the arguments given to new and sizeof(TypeId) as its first argument:
Sample:
new (a, b, c) TypeId;
// the function called by the compiler has to have the following signature:
operator new(std::size_t size, TypeOfA a, TypeOfB b, TypeOf C c);
if operator new fails to allocate storage, it can call new_handler, and hope it makes place. If there still is not enough place, new has to throw std::bad_alloc or derived from it. An allocator that has throw() (no-throw guarantee), it shall return a null-pointer in that case.
The C++ runtime environment will create an object of the type given by the type-id in the memory returned by the allocation function.
There are a few special allocation functions given special names:
no-throw new. That takes a nothrow_t as second argument. A new-expression of the form like the following will call an allocation function taking only std::size_t and nothrow_t:
Example:
new (std::nothrow) TypeId;
placement new. That takes a void* pointer as first argument, and instead of returning a newly allocated memory address, it returns that argument. It is used to create an object at a given address. Standard containers use that to preallocate space, but only create objects when needed, later.
Code:
// the following function is defined implicitly in the standard library
void * operator(std::size_t size, void * ptr) throw() {
return ptr;
}
If the allocation function returns storage, and the the constructor of the object created by the runtime throws, then the operator delete is called automatically. In case a form of new was used that takes additional parameters, like
new (a, b, c) TypeId;
Then the operator delete that takes those parameters is called. That operator delete version is only called if the deletion is done because the constructor of the object did throw. If you call delete yourself, then the compiler will use the normal operator delete function taking only a void* pointer:
int * a = new int;
=> void * operator new(std::size_t size) throw(std::bad_alloc);
delete a;
=> void operator delete(void * ptr) throw();
TypeWhosCtorThrows * a = new ("argument") TypeWhosCtorThrows;
=> void * operator new(std::size_t size, char const* arg1) throw(std::bad_alloc);
=> void operator delete(void * ptr, char const* arg1) throw();
TypeWhosCtorDoesntThrow * a = new ("argument") TypeWhosCtorDoesntThrow;
=> void * operator new(std::size_t size, char const* arg1) throw(std::bad_alloc);
delete a;
=> void operator delete(void * ptr) throw();
new-expression and arrays
If you do
new (possible_arguments) TypeId[N];
The compiler is using the operator new[] functions instead of plain operator new. The operator can be passed a first argument not exactly sizeof(TypeId)*N: The compiler could add some space to store the number of objects created (necassary to be able to call destructors). The Standard puts it this way:
new T[5] results in a call of operator new[](sizeof(T)*5+x), and
new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f).
What new does differently form malloc is the following:
It constructs a value in the allocated memory, by calling operator new. This behaviour can be adapted by overloading this operator, either for all types, or just for your class.
It calls handler functions if no memory can be allocated. This gives you the opportunity to free the required memory on the fly if you have registered such a handler function beforehand.
If that doesn't help (e.g. because you didn't register any function), it throws an exception.
So all in all, new is highly customizable and also does initialization work besides memory allocation. These are the two big differences.
Although malloc/free and new/delete have different behaviors, they both do the same thing at a low level: manage dynamically allocated memory. I'm assuming this is what you're really asking about. On my system, new actually calls malloc internally to perform its allocation, so I'll just talk about malloc.
The actual implementation of malloc and free can vary a lot, since there are many ways to implement memory allocation. Some approaches get better performance, some waste less memory, others are better for debugging. Garbage collected languages may also have completely different ways of doing allocation, but your question was about C/C++.
In general, blocks are allocated from the heap, a large area of memory in your program's address space. The library manages the heap for you, usually using system calls like sbrk or mmap. One approach to allocating blocks from the heap is to maintain a list of free and allocated blocks which stores block sizes and locations. Initially, the list might contain one big block for the whole heap. When a new block is requested, the allocator will select a free block from the list. If the block is too large, it can be split into two blocks (one of the requested size, the other of whatever size is left). When an allocated block is freed, it can be merged with adjacent free blocks, since having one big free block is more useful than several small free blocks. The actual list of blocks can be stored as separate data structures or embedded into the heap.
There are many variations. You might want to keep separate lists of free and allocated blocks. You might get better performance if you have separate areas of the heap for blocks of common sizes or separate lists for those sizes. For instance, when you allocated a 16-byte block, the allocator might have a special list of 16-byte blocks so allocation can be O(1). It may also be advantageous to only deal with block sizes that are powers of 2 (anything else gets rounded up). For instance, the Buddy allocator works this way.
"new" does a lot more than malloc. malloc simply allocates the memory - it doesn't even zero it for you. new initialises objects, calls contructors etc. I would suspect that in most implementations new is little more than a thin wrapper around malloc for basic types.
In C:
malloc allocates a chunk of memory of a size that you provide in an argument, and returns back a pointer to this memory.
The memory is declared on the heap, so make sure to deallocate it when you are finished.