Geoffrey Irving
Geoffrey Irving

Reputation: 6613

Is it possible to make a C++ type that mimics the constructor semantics of fundamental types?

The constructor semantics of int/double/etc. are:

int a; // uninitialized
int b = int(); // zero initialized
int c = int(4); // four

Is it possible to define a class with exactly the same behavior? I.e., one that has both uninitialized and initialized default constructors? I believe this is impossible, and currently work around it by making a constructor that compiles only when called with 0, but want to make sure there isn't a way to exactly mimic fundamental types.

Upvotes: 1

Views: 198

Answers (8)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136266

If no constructors defined:

struct A { int x; };

A a; // default-initialized (unintialized)
A b = A(); // value-initialized
A c = { 4 }; // four

Upvotes: 2

bames53
bames53

Reputation: 88155

Perhaps you could do something like this:

template<typename T>
struct uninitialized {
    static_assert(std::is_trivially_destructible<T>::value,"T must have trivial dtor");

    alignas(T) char raw[sizeof(T)];

    template<typename... Us>
    T &initialize(Us &&... us) {
        return *(new (raw) T(std::forward<Us>(us)...));
    }

    T &get() { return reinterpret_cast<T&>(raw); }
};

trivial destructor is required because otherwise you'd have to keep track of whether the object had been constructed or not in order to destroy it appropriately.

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 477070

Aggregate class types have essentially the behaviour you like:

struct Foo { int a; int b; };

Foo x;   // x.a, x.b uninitialized

Foo * p = new Foo(); // p->x, p->y value-initialized, i.e. zero

Foo y { 1, 2 }; // brace-initialization does what you think

Foo z { };      // brace-initialization can also "fake" value-init for automatics

For aggregates, default- and value-initialization propagate recursively to members.

Of course you can also make a non-aggregate that leaves a member uninitialized:

struct Bar
{
    int a;
    int b;
    Bar() : a() { }  // no b!
    Bar(int a_, int b_) : a(a_), b(b_) { }
};

Bar x;   // x.a is value-, x.b is default-initialized

Upvotes: 0

Jody Hagins
Jody Hagins

Reputation: 28409

The default contractor will always be called. There are lots of "tricks" you can do, but it depends on why you want this behavior, and what you want the user code to look like. You can define a special constructor that just doe not do anything with the data members and call that. Or, you can do lots of different things... one option is this...

You can also play with templates...

struct uninitialized_ctor {};

class Foo
{
public:
  int x;
  Foo() : x(42)
  {
    std::cout << "Foo::Foo\n";
  }
protected:
  Foo(uninitialized_ctor const &)
  {
    std::cout << "Foo::Foo - uninitialized\n";
  }
};


struct UninitializedFoo : public Foo
{
  UninitializedFoo()
    : Foo(uninitialized_ctor())
  {
    // Does not call base class ctor...
    std::cout << "UninitializedFoo\n";
  }
};


int main(int, char *[])
{
  Foo foo1;
  UninitializedFoo foo2;
  Foo * f1 = new Foo();
  Foo * f2 = new UninitializedFoo();

  std::cout << foo1.x << '\n' << foo2.x << '\n' << f1->x << '\n' << f2->x << '\n';
}

BUT -- it depends on what your real goal is... and how it impacts users of the code...

Upvotes: 1

D_E
D_E

Reputation: 1196

It is impossible, default constructor will be called in any case.

Upvotes: 0

Kaz
Kaz

Reputation: 58578

"uninitialized construction" is oxymoronic.

Lack of initialization in construction only occurs as a result of bugs (failing to recursively construct the entire object).

If a C++ class has a constructor, it is called. If for any reason it cannot be called, then that situation is erroneous (for instance wrong construction arguments passed that don't match any constructor).

A C++ class can contain members which are of basic types, and its constructors can neglect to initialize those members.

This could be exploited for optimization: if you have a complex initialization which happens later, you can avoid the overhead of writing to those members.

That would be the way to do it, rather than trying to create an entire class that can be left uninitialized.

If you really want that, a way to emulate it would be to create a POD (plain old datastructure) without any constructors, and then use some additional techniques so that it can be used in ways that guarantee its initialization. For instance make a derived class from it which adds construction, or make use of the curiously repeating template pattern, etc.

Then you can still use the POD directly if you want it not initialized.

Upvotes: 2

nothrow
nothrow

Reputation: 16168

class A { 
public:
    A() {}

};
A* a = (A*)malloc(sizeof(A));

(kids, don't do this at home. Don't do this at all!)

Upvotes: -1

littleadv
littleadv

Reputation: 20272

It is impossible, because as opposed to the built-in types, your class constructor will always be called.

If you really want to do "uninitialized" object (why ???? Don't you have enough bugs because of uninitialized variables?), you'll have to do tricks with placement new, probably.

Upvotes: 2

Related Questions