deferred — это легковесный шаблон-обертка для отложенного создания объектов в C++. Его основная цель — решить проблему работы с классами, у которых отсутствует конструктор по умолчанию.
Некоторые классы требуют аргументов для создания объекта, например:
struct NoDefaultCtor {
int value;
NoDefaultCtor() = delete;
NoDefaultCtor(int v) : value(v) {}
};В таких случаях нельзя объявить объект и отложить его конструирование до более позднего момента:
NoDefaultCtor obj; // Compile error: no default constructor available
...
// `obj` should be constructed hereОбычно это приводит к необходимости использовать указатели или другие обертки:
NoDefaultCtor* ptr;
...
ptr = new NoDefaultCtor(0);Позволяет объявить объект заранее и инициализировать позже:
deferred<NoDefaultCtor> obj;
...
obj = NoDefaultCtor(42);
auto value = obj->value; // okТакже допускает инициализацию объекта вне списка инициализации класса:
class Resource {
NoDefaultCtor obj;
deferred<NoDefaultCtor> dobj;
public:
Resource() noexcept
: obj{ 0 } // `obj` must be constructed here and only here
{
dobj = NoDefaultCtor(0); // `dobj` can be constructed anywhere
}
};Обращение к неинициализированному объекту через deferred никак не проверяется и приводит к неопределенному поведению (UB)
deferred<NoDefaultCtor> obj; // Not initialized
auto value = obj->value; // UBdeferred предоставляет легкий доступ к объекту через:
get()для явного получения ссылки на объектoperator->()operator*()
deferred<T> не имеет накладных расходов, относительно использования объекта T напрямую.
Размер объекта также не меняется:
static_assert(sizeof(deferred<T>) == sizeof(T)); // For any type T#include <iostream>
#include "deferred.h"
deferred<NoDefaultCtor> obj;
void foo()
{
std::cout << obj->value << std::endl;
std::cout << (*obj).value << std::endl;
std::cout << obj.get().value << std::endl;
}
int main()
{
obj = NoDefaultCtor(42);
foo();
NoDefaultCtor& ref = obj;
const NoDefaultCtor& cref = obj;
ref.value = -1;
std::cout << ref.value << std::endl;
std::cout << cref.value << std::endl;
return 0;
}class Resource {
deferred<NoDefaultCtor> obj;
public:
Resource() noexcept = default;
~Resource() noexcept = default;
void set(int n)
{
obj = NoDefaultCtor(n);
}
void useObject()
{
std::cout << obj->value << std::endl;
}
};
Resource res;
...
res.set(42);
res.useObject();