Paolo.Bolzoni
Paolo.Bolzoni

Reputation: 2576

What is the most idiomatic way to "delay" the construction of a C++ object?

For built-in types, like int, you can delay the initialization simply writing nothing. Is there a way to do the same for C++ objects?

I wrote this code that does the job, but I was wondering if there is an idiomatic way. If so, what is it? Was it even possible before the introduction of aligned storage?

#include <utility>
#include <type_traits>

template <typename T>
struct delayed {
    delayed() { unset_init(); }
    template <typename...Args> void init(Args&&... args) {
        new ( memory() ) T(std::forward<Args>(args)...);
        set_init();
    }

    operator T*() {
        return memory();
    }

    ~delayed() {
        if (get_init()) {
            memory()->~T();
            unset_init();
        }
    }

private:
    T* memory() { return reinterpret_cast<T*>(&bytes_); }
    unsigned char* raw_memory() { return reinterpret_cast<unsigned char*>(&bytes_); }

    unsigned char& init() { return *( raw_memory() + sizeof(T) ); }
    bool get_init() { return init() != 0; }
    void set_init() { init() = 1; }
    void unset_init() { init() = 0; }

    typename std::aligned_storage<sizeof(T) + 1, alignof(T)>::type bytes_{};
};

Upvotes: 12

Views: 4344

Answers (4)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145359

First, an int variable is a C++ object. Presumably when you talk about C++ objects as opposed to int, you mean class type objects. But not just class type objects, because you can do this:

struct Blah{ int x; int y; };

auto main() -> int
{
    Blah o;    // Uninitialized, indeterminate value.
    // Whatever
    o = {6, 7};
};

So probably you mean object of a class type with at least one user-defined constructor.

The most common ways to delay initialization of such an object, relative to the declaration of something used to access it, include

  • std::vector as an expanding array,
  • direct dynamic allocation (regardless of how the lifetime is managed), and
  • refactoring the code,

… where the refactoring essentially is about moving later usage code to a function or functions.

For example, the ugly and inefficient delayed-initialization code

unique_ptr<MyClass> p;

if( condition() )
{
    // Some code here, then
    p.reset( new MyDerivedA( 123 ) );
}
else
{
    // Some code here, then
    p.reset( new MyDerivedB( "andromeda" ) );
}
// Code using *p here.

… might be refactored as

void foo( MyClass&& o )
{
    // Code using o here.
}

…
if( condition() )
{
    // Some code here, then
    foo( MyDerivedA( 123 ) );
}
else
{
    // Some code here, then
    foo( MyDerivedB( "andromeda" ) );
}

Less common ways include

  • placement new in some suitably aligned byte array, like in your code, and

  • if your class is movable, using an Optional_ class (Barton-Nackman Fallible, Boost and C++17 optional) that supports move assignment.

Whether these techniques can be regarded as idiomatic for the purpose of delaying initialization, is, I think, quite subjective, personal opinion.

Upvotes: 6

Jens
Jens

Reputation: 9416

If you can live with a potential copy or move instead of directly initializing you could use a union. I would prefer an optional, either from std::experimental, C++17 or e.g. Boost.

#include <iostream>

struct S {
    S(int, float) {std::cout << "S::S()" << std::endl;}
    ~S() {std::cout << "S::~S()" << std::endl;}
};

template<typename T>
union Delayed {
    bool initialized;
    T obj;

    Delayed(): initialized(false) {}
    ~Delayed() {}
};

int main() {
    Delayed<S> d;

    std::cout << 1 <<std::endl;

    d.obj = S(1, 1.0);

    return 0;
}

Upvotes: 1

skypjack
skypjack

Reputation: 50550

I don't know about an idiomatic way of doing that.
The other answers are quite interesting indeed (std::optional is to become part of the standard library, but can it be considered idiomatic?).
Here is one more example of a delayed initialization based on another idiom, the pimpl (minimal, working example):

#include <memory>
#include <iostream>

struct I {
    void doSomething(int i) { val = i; }
    int getSomeData() { return val; }
    int val;
};

class C {
    static I& initialized(C &c) {
        std::cout << "is initialized" << std::endl;
        return *(c.impl);
    }

    static I& uninitialized(C &c) {
        std::cout << "was uninitialized" << std::endl;
        c.impl = std::make_unique<I>();
        c.getter = &initialized;
        return c.getter(c);
    }

public:
    C(): impl{nullptr}, getter{&uninitialized} {}

    void doSomething(int i) { getter(*this).doSomething(i); }
    int getSomeData() { return getter(*this).getSomeData(); }

private:
    using Getter = I&(*)(C &);
    std::unique_ptr<I> impl;
    Getter getter;
};

int main() {
    C c;
    c.doSomething(42);
    c.getSomeData();
}

In this case, the class is nothing more than a wrapper for a bunch of data and functions contained in another class.
By delaying the construction of the internal representation, you are actually delaying the initialization of the outer class.

Upvotes: 1

Brian Bi
Brian Bi

Reputation: 119382

In C++17 and later I expect the preferred idiom will be std::optional<T>. In C++11 and C++14 it seems that std::unique_ptr<T> is common though it has the obvious drawback of requiring a heap allocation.

Usage:

std::optional<T> t; // initially empty
// do some stuff
// now we're ready to create the T value
t.emplace(foo, bar); // constructs the T with foo, bar as args

Upvotes: 24

Related Questions