Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize a variable after a function call, like the new-expression provides?

Currently I am working on custom memory allocation and one of the drawbacks is that I have to write multiple lines to achieve the same result that the new-expression provides with just one simple call.

Simple initialization:

MyClass *obj = new MyClass(3.14);

Less simple initialization:

void *obj_mem = alloc->Allocate(sizeof MyClass, alignof(MyClass));
MyClass *obj = new(obj_mem) MyClass(3.14);

I am going to provide my project group with allocators such as that one, and want them to actually use them, instead of falling back on calling new, since we'll need these faster allocators to manage our memory.

But for that to happen, I will have to devise the simplest possible syntax to initialize a variable with my custom allocators.


My Solution

My best bet was overriding operator new in each class, since it is the allocation function for the new-expression.

class MyClass
{
    ...

    void* operator new(size_t size, Allocator *alloc)
    {
        return alloc->Allocate(size, alignof(MyClass));
    }
}

And then the syntax to initialize a variable becomes what I ultimately want:

MyClass *obj = new(alloc) MyClass(3.14);

However, it would be great if I could have a general equivalent of the above. So I wouldn't have to override operator new for each class.

like image 853
Nikita Avatar asked Dec 04 '16 05:12

Nikita


People also ask

How do you initialize a variable in a function in C++?

Variable initialization in C++ There are two ways to initialize the variable. One is static initialization in which the variable is assigned a value in the program and another is dynamic initialization in which the variables is assigned a value at the run time.

How do you initialize a variable in C?

Different ways of initializing a variable in Cint a, b; a = b = 10; int a, b = 10, c = 20; Method 5 (Dynamic Initialization : Value is being assigned to variable at run time.)

What does it mean to initialize a variable in C++?

Initialization of a variable provides its initial value at the time of construction. The initial value may be provided in the initializer section of a declarator or a new expression. It also takes place during function calls: function parameters and the function return values are also initialized.

Can we initialize variable in class in C++?

In C++, class variables are initialized in the same order as they appear in the class declaration. Consider the below code. The program prints correct value of x, but some garbage value for y, because y is initialized before x as it appears before in the class declaration.


1 Answers

Kill new entirely. You have to bundle the creation with destruction anyhow.

template<class T>
struct destroy {
  Alloc* pool = nullptr;
  void operator()(T* t)const { 
    ASSERT(t);
    t->~T();
    ASSERT(alloc);
    alloc->Dealloc( t );
  }
};
template<class T>
using my_unique_ptr = std::unique_ptr<T, destroy<T>>;

namespace details{
  template<class T, class...Args>
  my_unique_ptr<T> my_make_unique( Alloc* alloc, Args&&...args ) {
    void* p_data = alloc->Allocate(sizeof(T), alignof(T));
    try {
      T* ret = ::new(p_data) T(std::forward<Args>(args)...);
      return {ret, destroy<T>{alloc}};
    } catch (...) {
      alloc->Dealloc( p_data );
      throw;
    }
  }
}
/// usual one:
template<class T, class...Args>
my_unique_ptr<T> my_make_unique( Alloc* alloc, Args&&...args ) {
  return details::my_make_unique<T>( alloc, std::forward<Args>(args)... );
}
// permit leading il:
template<class T, class U, class...Args>
my_unique_ptr<T> my_make_unique( Alloc* alloc, std::initializer_list<U> il, Args&&...args ) {
  return details::my_make_unique<T>( alloc, il, std::forward<Args>(args)... );
}
// for {} based construction:
template<class T>struct tag_t{using type=T;};
template<class T>using no_deduction=typename tag_t<T>::type;
template<class T>
my_unique_ptr<T> my_make_unique( Alloc* alloc, no_deduction<T>&&t ) {
  return details::my_make_unique<T>( alloc, std::move(t) );
}

now my_make_unique takes an Alloc* and construction arguments, and it returns a smart pointer with destruction code bundled.

This unique pointer can be passed to a std::shared_ptr<T> implicitly (via move).

like image 52
Yakk - Adam Nevraumont Avatar answered Oct 14 '22 00:10

Yakk - Adam Nevraumont