skydoor
skydoor

Reputation: 25868

How do I declare an array of objects whose class has no default constructor?

If a class has only one constructor with one parameter, how to declare an array? I know that vector is recommended in this case. For example, if I have a class

class Foo{

public:
Foo(int i) {}

}

How to declare an array or a vector which contains 10000 Foo objects?

Upvotes: 14

Views: 18804

Answers (13)

en4bz
en4bz

Reputation: 1132

The proper way is use to std::aligned_storage. You will have to manually construct and destruct items as well as reintrepret_cast when you want to access an item. I recommend you write a small wrapper class around storage_t to take care of this. Someone mentioned using boost::optional which uses a bool and a storage_t under the hood. This method saves you a bool.

template<typename T>
using storage_t = typename std::aligned_storage<sizeof(T), alignof(T)>::type;

struct Foo;

size_t i = 55;
storage_t<Foo> items[1000]; // array of suitable storage for 1000 T's
new (reintrepret_cast<Foo*>(items + i)) Foo(42); // construct new Foo using placement new
*reintrepret_cast<Foo*>(items + i) = Foo(27);    // assign Foo
reintrepret_cast<Foo*>(items + i)->~Foo()        // call destructor

Upvotes: 0

user4173758
user4173758

Reputation:

Try this.

Foo **ppInstances=0;
    size_t total_instances = 10000;

    for(int parent=0;parent < total_instances;parent++){
        ppInstances[parent]=new Foo( parent ); 
        ppInstances++;
    }
    for(int parent=0;parent < total_instances;parent++){
        delete *ppInstances;
        ppInstances--;
    }

Upvotes: 0

Dan Moulding
Dan Moulding

Reputation: 220523

sbi had the best answer for plain arrays, but didn't give an example. So...

You should use placement new:

char *place = new char [sizeof(Foo) * 10000];
Foo *fooArray = reinterpret_cast<Foo *>(place);
for (unsigned int i = 0; i < 10000; ++i) {
    new (fooArray + i) Foo(i); // Call non-default constructor
}

Keep in mind that when using placement new, you are responsible for calling the objects' destructors -- the compiler won't do it for you:

// In some cleanup code somewhere ...
for (unsigned int i = 0; i < 10000; ++i) {
    fooArray[i].~Foo();
}

// Don't forget to delete the "place"
delete [] reinterpret_cast<char *>(fooArray);

This is about the only time you ever see a legitimate explicit call to a destructor.

NOTE: The first version of this had a subtle bug when deleting the "place". It's important to cast the "place" back to the same type that was newed. In other words, fooArray must be cast back to char * when deleting it. See the comments below for an explanation.

Upvotes: 8

Rajendra Uppal
Rajendra Uppal

Reputation: 19914

class single
{
    int data;
public:
    single()
    {
        data = 0;
    }
    single(int i)
    {
        data = i;
    }
};

// in main()
single* obj[10000];
for (unsigned int z = 0; z < 10000; z++) 
{
    obj[z] = new single(10);
}

Upvotes: 1

CB Bailey
CB Bailey

Reputation: 791699

For an array you would have to provide an initializer for each element of the array at the point where you define the array.

For a vector you can provide an instance to copy for each member of the vector.

e.g.

std::vector<Foo> thousand_foos(1000, Foo(42));

Upvotes: 15

Bill
Bill

Reputation: 14685

If it makes sense for your class, you could provide a default value for your constructor parameter:

class Foo
{ 
public: 
  explicit Foo(int i = 0); 
}

Now you have a default constructor. (A "default constructor" is a constructor that can be called with no arguments: FAQ)

I'd also recommend making your constructor explicit, as I did above. It will prevent you from getting Foos from ints when you don't want request them.

Upvotes: 0

bta
bta

Reputation: 45057

In straight C, using int foo[10000] = {1}; will initialize the first array item to 1 and the remainder of the array to zero. Does C++ not auto-initialize unspecified array members, or does this require a default constructor?

Upvotes: 0

AnT stands with Russia
AnT stands with Russia

Reputation: 320421

You have to use the aggregate initializer, with 10000 of inidividual initializers between the {}

Foo array[10000] = { 1, 2, 3, ..., 10000 };

Of course, specifying 10000 initializers is something from the realm of impossible, but you asked for it yourself. You wanted to declare an array of 10000 objects with no default constructor.

Upvotes: 1

Manuel
Manuel

Reputation: 13099

Another option might be to use an array of boost::optional<Foo>:

boost::optional<Foo> foos[10]; // No construction takes place
                               // (similar to vector::reserve)

foos[i] = Foo(3); // Actual construction

One caveat is that you'll have to access the elements with pointer syntax:

bar(*foos[2]); // "bar" is a function taking a "Foo"

std::cout << foos[3]->baz(); // "baz" is a member of "Foo"

You must also be careful not to access an unitialized element.

Another caveat is that this not a true replacement for an array of Foo, as you won't be able to pass it to a function that expects the latter.

Upvotes: 0

sbi
sbi

Reputation: 224049

The only way to define an array of a class with no default constructor would be to initialize it right away - not really an option with 10000 objects.

You can, however, allocate enough raw memory whichever way you want and use placement new to create the objects in that memory. But if you want to do this, it's better to use std::vector which does exactly that:

#include <iostream>
#include <vector>

struct foo {
    foo(int) {}
};

int main()
{
    std::vector<foo> v;
    v.resize(10000,foo(42));
    std::cout << v.size() '\n';
    return 0;
}

Upvotes: 1

Rob Kennedy
Rob Kennedy

Reputation: 163257

When you declare an object that has no default constructor, you must initialize it in the declaration.

Foo a; // not allowed
Foo b(0); // OK

The same goes for arrays of such types:

Foo c[2]; // not allowed
Foo d[2] = { 0, 1 }; // OK
Foo e[] = { Foo(0), Foo(1), Foo(2) }; // also OK

In your case, you'll probably find it impractical to initialize all 10,000 elements like that, so you might wish to rethink whether the class really shouldn't have a default constructor.

Upvotes: 4

fogo
fogo

Reputation: 304

Actually, you can do it as long you use an initialization list, like

Foo foos[4] = { Foo(0),Foo(1),Foo(2),Foo(3) };

however with 10000 objects this is absolutely impractical. I'm not even sure if you were crazy enough to try if the compiler would accept an initialization list this big.

Upvotes: 13

Cory Petosky
Cory Petosky

Reputation: 12646

You'd need to do an array of pointers to Foo.

Foo* myArray[10000];
for (int i = 0; i < 10000; ++i)
    myArray[i] = new Foo(i);

Upvotes: 4

Related Questions