Type information in placement new - c++

I have a placement new operator that, quite predictably, allocates memory from a pool. However, I also need to know the object type to set up some meta fields. I could pass it as a second argument to placement new as a string, but since I specify the type when calling new anyway, isn't there any way to get it implicitly?
E.g. I could do this:
void* operator new(size_t count, Pool* pool, const char* type)
{
return pool->alloc(count, type); // type is used to associate metadata with the allocated chunk
}
Car* car = new(pool, "Car") Car(...);
But can't I do something like this?
template<class T>
void* operator new(size_t count, Pool* pool)
{
return pool->alloc(count, typeid(T).name());
}
Car* car = new(pool) Car(...);

No, sorry. Except for member allocator functions, which only work for class types you control, C++ neither uses the class type to select an operator new function nor provides any standard way for an operator new function to determine the type of the calling new-expression (if any).
You could give your Pool class a template member function to take care of both allocating and constructing:
template<typename T, typename... Args>
T* Pool::create(Args&& ... args) {
void* ptr = alloc(count, typeid(T).name());
try {
return ::new(ptr) T(std::forward<Args>(args)...);
} catch (...) {
dealloc(ptr);
throw;
}
}
// ...
Car* car = pool->create<Car>(vroom);
(Other comments about stuff you might already know: Remember to implement a matching placement-delete in case a class constructor throws an exception. Consider making an Allocator interface for compatibility with the standard library.)

Related

Overalignment of an existing type in c++17

Given an existing type T, it is possible to overalign it on the stack with the alignas() keyword:
alignas(1024) T variable;
For dynamic allocation, we have a cumbersome syntax :
T *variable = new (std::align_val_t(1024)) T;
However, there are two problems with this syntax:
Microsoft's compiler emits error C2956 although the syntax is valid;
There seems to be no corresponding operator for destruction and aligned delete.
A workaround seems would be the definition of a new type that encapsulates T:
alignas(1024)
struct AlignedType {
T _;
};
Alignedtype variable = new AlignedType; // Properly aligned in c++17
delete variable; // Suitable aligned deallocation function called in c++17
This workaround is messy, if T's constructor has parameters, we must add some syntaxic shenanigan to forward constructor arguments, and we need to access variable._ to get the real content.
Inheritance is a bit simpler, but if T is a fundamental type (like uint32_t), we can't use inheritance.
My question is as follow:
Does something like
using AlignedType = alignas(32) T;
is possible (the above does not compile) or is it just not possible to dynamically allocate an existing type using custom alignment without resorting to syntaxic complexities ?
It is not possible to achieve the equivalent of your hypothetical:
using AlignedType = alignas(32) T;
There is no such thing as a type that is equivalent to another type but with different alignment. If the language allowed something like that to exist, imagine all the extra overload resolution rules we would have to add to the language.
The syntax
new (std::align_val_t(1024)) T;
should work. However, MSVC has a bug where it considers ::operator new(std::size_t, std::align_val_t) to be a "placement allocation function" rather than a "usual allocation function". This leads to the error you are seeing, where it complains that a placement allocation function matches a usual deallocation function.
(It seems that it is the standard's fault for not being clear: CWG2592. However, MSVC is to blame too; why did they choose to interpret the standard in a way that makes new (std::align_val_t(x)) T illegal?)
A workaround is to implement your own operator new and matching operator delete that delegate to the ones that you actually want to call:
struct alignment_tag {};
void* operator new(std::size_t size, alignment_tag, std::align_val_t alignment) {
return operator new(size, alignment);
}
void operator delete(void* p, alignment_tag, std::align_val_t alignment) {
operator delete(p, alignment);
}
Now you can do
T *variable = new (alignment_tag{}, std::align_val_t(1024)) T;
I personally would wrap this in something like:
template <class T>
struct AlignedDeleter {
AlignedDeleter(std::align_val_t alignment) : alignment_(alignment) {}
void operator()(T* ptr) const {
ptr->~T();
::operator delete(ptr, alignment_);
}
std::align_val_t alignment_;
};
template <typename T>
using AlignedUniquePtr = std::unique_ptr<T, AlignedDeleter<T>>;
template <typename T, typename... Args>
AlignedUniquePtr<T> make_unique_aligned(std::align_val_t alignment, Args&&... args) {
return AlignedUniquePtr<T>(new (alignment_tag{}, alignment) T(std::forward<Args>(args)...), AlignedDeleter<T>(alignment));
}
(You can always call .release() if you need to.)

Is there a c++ counterpart to posix_memalign?

When I call posix_memalign to allocate aligned memory for an object of type Foo in my C++ code, I am required to do a reinterpret_cast of the address of that pointer to void**.
In general when I encounter this situation, it implies that I am missing some language feature. That is, it feels like I am calling malloc in c++ when I should be calling new.
,
Is there a type-aware new equivalent for aligned memory allocation in c++?
I will start with the core advice first.
Foo* aligned_foo() {
void* raw = 0;
if(posix_memalign(&raw, 8, sizeof(Foo)))
return 0; // we could throw or somehow communicate the failure instead
try{
return new(raw) Foo();
}catch(...){
free(raw);
throw;
}
}
then when you are done with the Foo* foo, do a foo->~Foo(); free(foo); instead of delete.
Note the lack of reinterpret_casts.
Here is an attempt to make it generic:
// note: stateless. Deleting a derived with a base without virtual ~base a bad idea:
template<class T>
struct free_then_delete {
void operator()(T*t)const{
if(!t)return;
t->~T();
free(t);
};
};
template<class T>
using aligned_ptr=std::unique_ptr<T,free_then_delete<T>>;
// the raw version. Dangerous, because the `T*` requires special deletion:
template<class T,class...Args>
T* make_aligned_raw_ptr(size_t alignment, Args&&...args) {
void* raw = 0;
if(int err = posix_memalign(&raw, alignment, sizeof(T)))
{
if (err==ENOMEM)
throw std::bad_alloc{};
return 0; // other possibility is bad alignment: not an exception, just an error
}
try {
// returns a T*
return new(raw) T(std::forward<Args>(args)...);
} catch(...) { // the constructor threw, so clean up the memory:
free(raw);
throw;
}
}
template<class T,class...Args> // ,class... Args optional
aligned_ptr<T> make_aligned_ptr(size_t alignment=8, Args&&...args){
T* t = make_aligned_raw_ptr<T>(alignment, std::forward<Args>(args)...);
if (t)
return aligned_ptr<T>(t);
else
return nullptr;
}
The unique_ptr alias aligned_ptr bundles the destroyer along with the pointer -- as this data requires destruction and free, not delete, this makes it clear. You can still .release() the pointer out, but you still have to do the steps.
Actually, you don't want to do a reinterpret_cast because then your Foo constructor isn't called. If you need to allocate memory from a special place, you then call placement new to construct the object in that memory:
void* alloc;
posix_memalign(&alloc, 8, sizeof(Foo));
Foo* foo = new (foo) Foo();
The only other way (pre C++11) would be overriding the new operator for your class. That works if you have a particular class that always requires this special allocation:
class Foo {
void* operator new(size_t size) {
void* newobj;
posix_memalign(&newobj, 8, sizeof(Foo));
return newobj;
}
};
Then anytime you call new Foo() it will invoke this allocator. See http://en.cppreference.com/w/cpp/memory/new/operator_new for more information. Overriding operator new and operator delete can be done for individual classes or globally.
C++11 has added native language support for alignment declarations and aligned allocation.
You can specify alignas(N) on your type in C++11 to specify the minimum alignment for new objects, which the default new will respect.
Example from cppreference:
struct alignas(16) sse_t { // SSE-safe struct aligned on 16-byte boundaries
float v[4];
};
then you can simply do
sse_t *ssevec = new sse_t;
For a replacement for posix_memalign, you can use std::aligned_storage<sizeof(T), N>, also in C++11.

Determine if an object is dynamically allocated or not in C++

I have a simple C++ class for which I need to know whether an object should be delete'd or not at a certain point in my program. The mechanism should be portable across platforms and modern C++ compilers.
One way of doing it I can think of is: have a member field which is not initialized by the constructor but instead is assigned by the overloaded operator new, like so:
class message
{
protected:
int id;
bool dynamic;
public:
message(int _id): id(_id)
{
// don't touch `dynamic` in the constructor
}
void* operator new(size_t size)
{
message* m = (message*)::operator new(size);
m->dynamic = true;
return m;
}
void operator delete(void* m)
{
if (((message*)m)->dynamic)
::operator delete(m);
}
};
Apart form that it "feels" wrong, what is wrong with this method?
Edit: should have mentioned that the object is either dynamic or static (and never stack-local) and thus is guaranteed to be either zeroed or initialized with new.
The constructor needs to set dynamic to false, and then instead of overriding new, you need a static method like:
static message *createMessage(int _id)
{
message *ret = new message(_id);
ret->dynamic = true;
return ret;
}
And then call that method instead of newing a message.
Don’t do this. Apart from the fact that it won’t work, an object shouldn’t be managing anything about its own lifetime. You can use a unique_ptr or shared_ptr with a custom deleter, and if the object is stack-allocated, you know at its allocation site; in that case, you can supply a no-op deleter such as the following:
struct null_deleter {
template<class T>
void operator()(const T*) const {}
};

Why does operator delete's signature take two parameters?

I've been reading about overloading new and delete (and related topics like placement new/delete). One thing that is confusing me thus far is that operator delete's standard signature is (at class-scope):
void operator delete(void *rawMemory, std::size_t size) throw();
Delete is called like this:
MyClass* ptr = new MyClass;
delete ptr;
So, how does delete ptr; provide the second parameter for size? Also, can I assume that the MyClass* is implicitly converted to the void* in this circumstance?
Short Answer:
new and delete operators are overloaded at class scope for optimizing allocation for objects of specific class. But there can be special scenarios due to certain beasts like Inheritance which may lead to allocation requests for more than the class size itself,Since the very purpose of new and delete overload is special tuning for objects of size sizeof(Base), nothing larger or smaller, these overloaded operators should forward all other wrong sized memory requests to ::operator new and ::operator delete, to be able to do so, the size parameter needs to be passed as an parameter.
Long Answer:
Consider a Special Scenario:
class Base
{
public:
static void * operator new(std::size_t size) throw(std::bad_alloc);
};
class Derived: public Base
{
//Derived doesn't declare operator new
};
int main()
{
// This calls Base::operator new!
Derived *p = new Derived;
return 0;
}
In the above sample, because of inheritance The derived class Derived inherits the new operator of the Base class. This makes calling operator new in a base class to allocate memory for an object of a derived class possible. The best way for our operator new to handle this situation is to divert such calls requesting the "wrong" amount of memory to the standard operator new, like this:
void * Base::operator new(std::size_t size) throw(std::bad_alloc)
{
if (size != sizeof(Base)) // if size is "wrong," i.e != sizeof Base class
{
return ::operator new(size); // let std::new handle this request
}
else
{
//Our implementation
}
}
While overloading the delete operator, One must also ensure that since class-specific operator new forwards requests of the "wrong" size to ::operator new, One MUST forward "wrongly sized" deletion requests to ::operator delete, Since the original operators are guaranteed to to handle these requests in a standard compliant manner.
So the custom delete operator will be something like this:
class Base
{
public:
//Same as before
static void * operator new(std::size_t size) throw(std::bad_alloc);
//delete declaration
static void operator delete(void *rawMemory, std::size_t size) throw();
void Base::operator delete(void *rawMemory, std::size_t size) throw()
{
if (rawMemory == 0)
{
return; // No-Op is null pointer
}
if (size != sizeof(Base))
{
// if size is "wrong,"
::operator delete(rawMemory); //delegate to std::delete
return;
}
//If we reach here means we have correct sized pointer for deallocation
//deallocate the memory pointed to by rawMemory;
return;
}
};
Further Reading:
The following C++-Faq entry talks about overloading new and delete in a standard compliant way and might be a good read for you:
How should i write iso c++ standard conformant custom new and delete operators?
So, how does delete ptr; provide the second parameter for size?
If pointer type is a class type with a virtual destructor, from dynamic information about object type. If it doesn't have a virtual destructor and pointee type matches pointer type - from compile time information about type size. Otherwise delete ptr is undefined behavior.
It's the compiler's job to remember the size to release when you call delete. For delete ptr;, it will pass sizeof(MyClass), for delete[] ptr; it has to remember the number of MyClass in the array, and pass the correct size. I have absolutely no idea how this oddball corner of the language came to be. I can't think of any other part of the language where the compiler must remember a run-time value for you.

Copy data from a pointer or chain of pointers (Object pointer, templates)

How the push_back of stl::vector is implemented so it can make copy of any datatype .. may be pointer, double pointer and so on ...
I'm implementing a template class having a function push_back almost similar to vector. Within this method a copy of argument should be inserted in internal allocated memory.
In case the argument is a pointer or a chain of pointers (an object pointer); the copy should be made of actual data pointed. [updated as per comment]
Can you pls tell how to create copy from pointer. so that if i delete the pointer in caller still the copy exists in my template class?
Code base is as follows:
template<typename T>
class Vector
{
public:
void push_back(const T& val_in)
{
T a (val_in); // It copies pointer, NOT data.
m_pData[SIZE++] = a;
}
}
Caller:
// Initialize my custom Vector class.
Vector<MyClass*> v(3);
MyClass* a = new MyClass();
a->a = 0;
a->b = .5;
// push MyClass object pointer
// now push_back method should create a copy of data
// pointed by 'a' and insert it to internal allocated memory.
// 'a' can be a chain of pointers also.
// how to achieve this functionality?
v.push_back(a);
delete a;
I can simply use STL vector to accomplish the tasks but for experiment purposes i'm writing a template class which does exactly the same.
Thanks.
if you have polymorphic object ( the pointed object may be more specialized than the variable ), I suggest you creating a virtual method called clone() that allocate a new pointer with a copy of your object:
Base* A::clone() {
A* toReturn = new A();
//copy stuff
return toReturn;
}
If you can't modify your Base class, you can use RTTI, but I will not approach this solution in this answer. ( If you want more details in this solution, please make a question regarding polymorphic cloning with RTTI).
If you have not a polymorphic object, you may allocate a new object by calling the copy constructor.
void YourVector::push_back(Base* obj) {
Base* copy = new Base(obj);
}
But it smells that what you are really needing is shared_ptr, avaliable in <tr1/memory> ( or <memory> if you use C++0x ).
Update based on comments
You may also have a two template parameters list:
template <typename T>
struct CopyConstructorCloner {
T* operator()(const T& t) {
return new T(t);
}
}
template <typename T, typename CLONER=CopyConstructorCloner<T> >
class MyList {
CLONER cloneObj;
public:
// ...
void push_back(const T& t) {
T* newElement = cloneObj(t);
// save newElemenet somewhere, dont forget to delete it later
}
}
With this approach it is possible to define new cloning politics for things like pointers.
Still, I recommend you to use shared_ptrs.
I think for this kind of problems it is better to use smart pointers ex: boost::shared_ptr or any other equivalent implementation.
There is no need to call new for the given datatype T. The push_back implementation should (must) call the copy-constructor or the assignment operator. The memory should have been allocated to hold those elemnets that are being pushed. The intial memory allocation should not call CTOR of type T. Something like:
T* pArray;
pArray = (T*) new BYTE[sizeof(T) * INITIAL_SIZE);
And then just put new object into pArray, calling the assignment operator.
One solution is to make a copy construction:
MyClass *p = new MyClass();
MyVector<MyClass*> v;
v.push_back(new MyClass(*p));
Update: From you updated question, you can definitely override push_back
template<typename T>
class MyVector {
public:
void push_back (T obj); // general push_back
template<typename TYPE> // T can already be a pointer, so declare TYPE again
void push_back (TYPE *pFrom)
{
TYPE *pNew = new TYPE(*pFrom);
// use pNew in your logic...
}
};
Something like this:
template<typename T>
class MyVector
{
T* data; // Pointer to internal memory
size_t count; // Number of items of T stored in data
size_t allocated; // Total space that is available in data
// (available space is => allocated - count)
void push_back(std::auto_ptr<T> item) // Use auto pointer to indicate transfer of ownership
/*void push_back(T* item) The dangerous version of the interface */
{
if ((allocated - count) == 0)
{ reallocateSomeMemory();
}
T* dest = &data[count]; // location to store item
new (dest) T(*item); // Use placement new and copy constructor.
++count;
}
// All the other stuff you will need.
};
Edit based on comments:
To call it you need to do this:
MyVector<Plop> data;
std::auto_ptr<Plop> item(new Plop()); // ALWAYS put dynamically allocated objects
// into a smart pointer. Not doing this is bad
// practice.
data.push_back(item);
I use auto_ptr because RAW pointers are bad (ie in real C++ code (unlike C) you rarely see pointers, they are hidden inside smart pointers).