I was thinking about some memory pool/allocation stuff I might write so I came up with this operator new overload that I want to use to facilitate reuse of memory. I'm wondering if there are any problems you guys can think of with my implementation (or any other possible ones).
#include <cstddef>
namespace ns {
struct renew_t { };
renew_t const renew;
}
template<typename T>
inline void * operator new(std::size_t size, T * p, ns::renew_t renew_constant) {
p->~T();
return p;
}
template<typename T>
inline void operator delete(void *, T *, ns::renew_t renew_constant) { }
It can be used like this
int main() {
foo * p(new foo()); // allocates memory and calls foo's default constructor
new(p, ns::renew) foo(42); // calls foo's destructor, then calls another of foo's constructors on the same memory
delete p; // calls foo's destructor and deallocates the memory
}
Please read http://www.gotw.ca/gotw/022.htm and http://www.gotw.ca/gotw/023.htm.
Really, you should define operator= rather than playing games with destructors. And adding an operator new (and operator delete, YUCK!) overload into the mix only increases the pain.
And, as C++ god Herb Sutter recommends in those links, you can simply define constructors in terms of operator=.
SHOULD be good, as long as you don't try something crazy and try to renew a subclass. Since you said this is for a pool, it should be fine.
That said, my only question is - what is more legible? This is a question of taste, but imagine that somebody else might need to look at the code. You're basically just contracting two simple and obvious statements into one that requires deeper knowledge of what the code internally does.
In my pool functions, I typically had two separate methods, one to destroy and one to construct, both them essentially doing what you do here (p->~T and new(p) T()), but at least you know exactly what they did.
The delete() operator doesn't call the destructor of the object, which is unexpected to me.
I had to do a double take on new(p, ns::renew) foo(42). To me that's simply not intuitive.
What you probably really want is to seperate the process of allocating memory and the process of constructing objects. For situations like this, you typically use "placement new" instead.
// Not exception safe!
void* p = ::operator new(sizeof(T)); // allocate raw memory
new(p) T(41); // construct a T at this memory location
p->~T(); // destruct T
new(p) T(42); // recreate a different T at the same memory location
p->~T(); // destruct T
::operator delete(p); // deallocate raw memory
In a real memory pool application, you would wrap the above lines into a MemoryPool class of some sort.
Of course, this only applies if you're actually dealing with memory directly for the purpose of implementing an actual memory pool or an allocator of a container. In other situations, you're better off overloading the = operator() as suggested by Potatoswatter.
Related
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.
Hello So I'm experimenting with creating objects and arrays with preallocated memory. For instance I have this following code:
int * prealloc = (int*)malloc(sizeof(Test));
Test *arr = new(prealloc) Test();
Where test is defined as follows:
class Test {
public:
Test() {
printf("In Constructor\n");
}
~Test() {
printf("In Destructor\n");
}
int val;
};
In this scenario if I call delete it will actually release the memory which is bad, b/c maybe I'm using some type of memory manager so this will sure cause some problems. I searched in the internet and the only solution that I found was to call the destructor explicitly and then call free:
arr->~Test();
free(arr);
Is there another way to do this? is there perhaps a way to call delete and tell it to just call the destructor and not to release the memory?
My second problem was when working with arrays, like the previous example you can pass to new the pre-allocated memory:
int * prealloc2 = (int*)malloc(sizeof(Test) * 10);
Test *arr2 = new(prealloc2) Test[10];
If I call delete[] it will not only call the destructor for each element in the array but it will also release the memory which is something I don't want. The only way I have found that it should be done is to go through the array and call the destructor explicitly, and then call free. Like with the regular none array operators is there a way to tell the operator to just call the destructors without releasing the memory?
One thing I did notice was that the new operator for an array will actually use the first 4 bytes to store the size of the array (I only tested this in visual studio with a 32 bit build) That would help me know how many elements the array has but there is still one problem. What if the array is a pointer array? for example:
Test **arr2 = new Test*[10];
Could someone help me out with these questions please.
It's normal and expected to directly invoke the destructor to destroy objects you've created with placement new. As far as any other way to do things, about the only obvious alternative is to use an Allocator object (which, at least 99% of the time, will just be a wrapper around placement new and directly invoking the destructor).
Generally speaking, you do not want to use new[] at all. You typically want to allocate your raw memory with operator new (or possibly ::operator new) and release it with the matching operator delete or ::operator delete.
You create objects in that memory with placement new and destroy them by directly invoking the destructor.
There is no other way to do it but to explicitly call the destructor as delete will also attempt to free the memory.
Using preallocated memory with placement new should be fairly rare in your code - a typical use case is when you're dealing with direct memory mapped hardware interfaces when you want/need to map an object on top of a fixed memory address - and is something I'd normally consider a code smell.
If you want to tweak the memory management for a specific class, you're much better off either using an STL container with a custom allocator or overload operators new and delete for that specific class.
Yes, this is the only way to do it. There is an asymmetry in being allowed to define new but not delete. [ Well, you can do the latter but it can only get called when new throws an exception (not handled properly below!)
You can use a templated destroy to achieve the same result:
class Test
{
public:
Test() {
printf("In Constructor\n");
}
~Test() {
printf("In Destructor\n");
}
int val;
};
class Allocator
{
public:
static void* allocate(size_t amount) { return std::malloc(amount);}
static void unallocate(void* mem) { std::free(mem);}
static Allocator allocator;
};
Allocator Allocator::allocator;
inline void* operator new(size_t size, const Allocator& allocator)
{
return allocator.allocate(size);
}
template<class T>
void destroy(const Allocator& allocator, T* object)
{
object->~T();
allocator.unallocate(object);
}
int main()
{
Test* t = new (Allocator::allocator) Test();
destroy(Allocator::allocator, t);
return 0;
}
I can override global operator new with different parameters, so for example I can have:
void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, int num) throw (std::bad_alloc);
which can be called separately as
int* p1 = new int; // calls new(size_t)
int* p2 = new(5) int; // calls new(size_t, int)
since each of these can potentially use some different allocation scheme, I would need a separate delete() function for each. However, delete(void*) cannot be overloaded in the same way! delete(void*) is the only valid signature. So how can the above case be handled?
P.S. I am not suggesting this is a good idea. This kind of thing happened to me and so I discovered this "flaw" (at least in my opinion) in c++. If the language allows the new overrides, it must allow the delete overrides, or it becomes useless. And so I was wondering if there is a way around this, not if this a good idea.
I can override global operator new with different parameters
Those are called placement allocation functions.
delete(void*) is the only valid signature.
No.
First, some terminology: A delete expression such as delete p is not just a function call, it invokes the destructor then calls a deallocation function, which is some overload of operator delete that is chosen by overload resolution.
You can override operator delete with signatures to match your placement allocation function, but that overload will only be used if the constructor called by the placement new expression throws an exception e.g.
struct E {
E() { throw 1; }
};
void* operator new(std::size_t n, int) throw(std::bad_alloc) { return new char[n]; }
void operator delete(void* p, int) { std::puts("hello!"); delete[] (char*)p; }
int main()
{
try {
new (1) E;
} catch (...) {
puts("caught");
}
}
The placement deallocation function which matches the form of placement new expression used (in this case it has an int parameter) is found by overload resolution and called to deallocate the storage.
So you can provide "placement delete" functions, you just can't call them explicitly. It's up to you to remember how you allocated an object and ensure you use the corresponding deallocation.
If you keep track of the different memory regions you allocate with your different new overloads, you can tag them with the version of new that was called.
Then at delete time you can look the address up to find which new was called, and do something different in each case.
This way you can guarantee that the correct logic is automatically associated with each different new overload.
As pointed out by baruch in the comments below, there is a performance overhead associated with the maintenance of the data you use for tracking, and this logic will also only work as long as the overloaded delete is not passed anything allocated using the default delete.
As far as tracking overhead, it seems to me that the minimum overhead method of tracking the type of the allocation is to allocate the amount requested, plus a small amount of additional space at the start of the allocated region in which to tag the request type (sized according to conservative alignment requirements). You can then look at this tag region on delete to determine which logic to follow.
There is a placement delete which matches the placement operator new. And you can't call it directly. This is because the placement delete is only used to deallocate memory when the constructor of the new'ed object throws.
void *operator new(size_t, Area&); // placement new
void operator delete(void*, Area&); // matching placement delete
...
Area &area;
SomeType *t=new(area) SomeType();
// when SomeType() throws then `delete(t,area)` from above is called
// but you can't do this:
delete (area) t;
A common way to overcome this, is to use write an overloaded "destroy" function, which accepts all kinds of parameters.
template<class T> void destroy(Area &a, T* &pt) //<-you can't do this with 'delete'
{
if (pt) {
pt->~T(); // run the destructor
a.freeMem(pt); // deallocate the object
pt=NULL; // nulls the pointer on the caller side.
}
}
The simple answer is: Do not do this. All forms of non-placement new are redundant in C++11 and horrifically unsafe, for example, return raw pointer. If you want to allocate objects in a custom place, then use a class with an allocate function if stateful or a free function if not. The best treatment for new and indeed, delete, is to excise them from your program with prejudice, with the possible exception of placement new.
Edit: The reason why it's useless for you is because you're trying to use it for a purpose which it was not intended for. All you can use the extra params for is stuff like logging or other behaviour control. You can't really change the fundamental semantics of new and delete. If you need stateful allocation, you must use a class.
You're wrong. It is possible to provide a placement delete.
I've this C++ class:
class test{
char* p;
SomeClass* someObject;
test(){
...
p = (char*) malloc(1000);
someObject = new SomeClass();
...
}
~test(){}
}
Do I need to call free(p) or delete someObject explicitly in test destructor in order to free their allocated memory or that memory will free automatically?
You need to free all dynamically allocated memory in the destructor. This does not get done automatically.
Your class contains two pointers, and essentially has no control over what these point to. In fact, these could point to objects that you are not allowed to delete, for example:
struct Foo {};
struct Bar {
Foo* f_;
Foo(Foo* f) : f(f_) {}
};
int main() {
Foo f;
Bas b(&f); // b has a Foo ptr, but should it delete it?
}
So you can see that it doesn't really make sense for pointer data members to be deleted automatically.
As a general rule, if your class manages resources1, then you should take care of copy construction and assignment; that means, you should either disable them if that makes sense for the class, or provide implementation for them because the compiler generated ones would not work. For detail discussion on this topic, see the rule of three, and extensive discussions on stackoverflow:
What is The Rule of Three?
Rule-of-Three becomes Rule-of-Five with C++11?
If you don't follow this rule, then the default copy constructor and assignment operation will make a shallow copy and you will have more than one instance having pointers to the same dynamically allocated objects, which they will all try to delete upon destruction.
You can avoid manually deleting objects created with new by using smart pointers. In your case, where the class obviously owns the dynamically allocated object,you should look at C++11's std::unique_ptr or boost::scoped_ptr
Finally, you can really avoid all memory management problems by avoiding pointers all together, unless you really need to. You could replace your char* by an std::string for example:
class test{
std::string p;
SomeClass someObject;
//test() : someObject() {} // default construction is probably OK...
};
1. That is, it allocates and deallocates memory, or opens and closes network connection, or creates and destroy mutexes and so on.
Yes, you have to free anything you malloc and delete everything you new.
You can also avoid that by not storing pointers in your class.
class test{
public:
std::string p;
SomeClass someObject;
};
Yes, you need.
If you don't want, you can use the Smart Pointer
Yes, you need to free them explicitly. Pointer as a data type does not have any destructor. Compiler/execution enviroment does not have any means to guess if pointer points to anything meaningfull or not. Even if the value is meaningfull, it may point to some static object for example. Or it can point to some field of a bigger object. Compiler is not doing any automatic cleanup on pointers.
The memory is technically leaked if you do not reclaim it when the instance of test is destructed. You could use a smart pointer instead to avoid calling free or delete explicitly in the destructor.
struct Free { void operator () (void *p) const { free(p); } };
class test {
std::unique_ptr<char, Free> p;
std::unique_ptr<SomeClass> someObject;
test () : p(static_cast<char *>(malloc(1000)),
someObject(new SomeClass)
{ //...
}
~test () {}
};
This uses the destructor of the smart pointer to perform the clean up action for you.
If test were only used as const global instances, then it is less important to implement the cleanup since the memory would not be reclaimed until the execution had ended anyway. But it is good practice to always implement the cleanup, because it would make the code correct now, and test may be used differently in the future.
I have a question regarding placement new syntax in C++. Are the following two code snippets functionally equivalent and can be used interchangeably (I am not implying that the second should be used, when the first one is suitable)?
#1
T* myObj = new T();
// Do something with myObj
delete myObj;
#2
char* mem = new char[sizeof(T)];
T* myObj = new (mem) T();
// Do something with myObj
myObj->~T();
delete[] mem;
Is there something I should be especially careful of, when I am using the placement new syntax like this?
They are not equivalent, because they have different behaviour if the constructor or the destructor of T throws.
new T() will free any memory that has been allocated before letting the exception propagate any further. char* mem = new char[sizeof(T)]; T* myObj = new (mem) T(); will not (and unless you explicitly do something to ensure that it gets freed you will have a leak). Similarly, delete myObj will always deallocate memory, regardless of whether ~T() throws.
An exact equivalent for T* myObj = new T();/*other code*/delete myObj; would be something like:
//When using new/delete, T::operator new/delete
//will be used if it exists.
//I don't know how do emulate this in
//a generic way, so this code just uses
//the global versions of operator new and delete.
void *mem = ::operator new(sizeof(T));
T* myObj;
try {
myObj = new (mem) T();
}
catch(...) {
::operator delete(mem);
throw;
}
/*other code*/
try {
myObj->~T();
::operator delete(mem);
}
catch(...) {
//yes there are a lot of duplicate ::operator deletes
//This is what I get for not using RAII ):
::operator delete(mem);
throw;
}
Since you're allocating raw memory, a closer equivalent would be:
void *mem = operator new(sizeof(T));
T *myobj = new(mem) T();
// ...
myobj->~T();
operator delete(mem);
Note that if you've overloaded ::operator new for a particular class, this will use that class' operator new, where yours using new char [] would ignore it.
Edit: though I should add that I'm ignoring the possibility of exceptions here. #Mankarse's answer seems (to me) to cover that part fairly well.
On a fundamental level, you're doing the same thing in both situations: i.e. you're instantiating a new object on the heap and you're releasing the memory, but in the second case you're (obviously) using the placement new operator.
In this case both of them would yield the same results, minus the differences if the constructor throws as Mankarse explained.
In addition, I wouldn't say that you can use them interchangeably, because the second case is not a realistic example of how placement new is used. It would probably make a lot more sense to use placement new in the context of a memory pool and if you're writing your own memory manager so you can place multiple T objects on the per-allocated memory (in my tests it tends to save about 25% CPU time). If you have a more realistic use case for placement new then there will be a lot more things that you should worry about.
Well, you are pre-allocating memory for your T object. And it should be fine. Nevertheless it makes sense if you will reuse allocated area one more time. Otherwise It will be slower.
Yes. Your example is too simple to demonstrate this, but the memory you allocated in advance, "mem," should manage the object stored within, "myObj."
Perhaps put a better way, scenario #1 allocates space on the heap, and constructs an object in that space. Scenario #2 allocates space on the heap, "mem," then constructs an object somewhere within that space.
Now, put a second object somewhere else within "mem." It gets complicated, right?
The construction and destruction of myObj are happening identically in both scenarios (except in the case of your constructor throwing an exception, as pointed out by Mankarse), but the allocator is taking care of your memory management for you in scenario #1, and not in scenario #2.
So, be careful of managing "mem" appropriately. One common approach is the following:
template<class T> void destroy(T* p, Arena& a)
{
if (p) {
p->~T(); // explicit destructor call
a.deallocate(p);
}
}