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
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.
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?
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.
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.
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--;
}
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