如果一个类只有一个带有一个参数的构造函数,那么如何声明一个数组?我知道在这种情况下推荐使用矢量。例如,如果我有一个班级
class Foo{
public:
Foo(int i) {}
}
如何声明包含10000个Foo对象的数组或向量?
答案 0 :(得分:15)
对于数组,您必须在定义数组的位置为数组的每个元素提供初始值设定项。
对于矢量,您可以为矢量的每个成员提供复制实例。
e.g。
std::vector<Foo> thousand_foos(1000, Foo(42));
答案 1 :(得分:12)
实际上,只要你使用初始化列表,就可以这样做,比如
Foo foos[4] = { Foo(0),Foo(1),Foo(2),Foo(3) };
然而,对于10000个物体,这绝对是不切实际的。如果编译器接受这么大的初始化列表,我甚至不确定你是否已经疯狂了。
答案 2 :(得分:8)
您应该使用新的展示位置:
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
}
请记住,当使用placement new时,你负责调用对象的析构函数 - 编译器不会为你执行此操作:
// 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);
这是你唯一一次看到对析构函数的合理显式调用。
注意:删除“地点”时,第一个版本有一个微妙的错误。将“地点”强制转换为新建的相同类型非常重要。换句话说,fooArray
在删除时必须转回char *
。请参阅以下评论以获得解释。
答案 3 :(得分:4)
你需要做一个指向Foo的指针数组。
Foo* myArray[10000];
for (int i = 0; i < 10000; ++i)
myArray[i] = new Foo(i);
答案 4 :(得分:2)
当声明一个没有默认构造函数的对象时,必须在声明中初始化它。
Foo a; // not allowed
Foo b(0); // OK
这种类型的数组也是如此:
Foo c[2]; // not allowed
Foo d[2] = { 0, 1 }; // OK
Foo e[] = { Foo(0), Foo(1), Foo(2) }; // also OK
在您的情况下,您可能会发现初始化所有10,000个元素是不切实际的,所以您可能希望重新考虑该类是否真的不应该有默认构造函数。
答案 5 :(得分:1)
您必须使用聚合初始化程序,在{}
Foo array[10000] = { 1, 2, 3, ..., 10000 };
当然,指定10000个初始化程序是不可能的,但是你自己要求它。你想声明一个10000个对象的数组,没有默认的构造函数。
答案 6 :(得分:1)
定义没有默认构造函数的类数组的唯一方法是立即初始化它 - 实际上不是10000对象的选项。
但是,您可以根据需要分配足够的原始内存,并使用放置new
在该内存中创建对象。但是如果你想这样做,那么最好使用std::vector
来做到这一点:
#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;
}
答案 7 :(得分:1)
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);
}
答案 8 :(得分:0)
另一种选择可能是使用boost::optional<Foo>
:
boost::optional<Foo> foos[10]; // No construction takes place
// (similar to vector::reserve)
foos[i] = Foo(3); // Actual construction
需要注意的是,您必须使用指针语法访问元素:
bar(*foos[2]); // "bar" is a function taking a "Foo"
std::cout << foos[3]->baz(); // "baz" is a member of "Foo"
您还必须注意不要访问单元化元素。
另一个警告是,这不是Foo
数组的真正替代,因为您无法将其传递给期望后者的函数。
答案 9 :(得分:0)
在直接C中,使用int foo[10000] = {1};
会将第一个数组项初始化为1
,并将数组的其余部分初始化为零。 C ++不会自动初始化未指定的数组成员,还是需要默认的构造函数?
答案 10 :(得分:0)
如果对您的类有意义,则可以为构造函数参数提供默认值:
class Foo
{
public:
explicit Foo(int i = 0);
}
现在您有一个默认构造函数。 (“默认构造函数”是可以不带参数调用的构造函数:FAQ)
我还建议你的构造函数是显式的,正如我上面所做的那样。当您不想要Foo
时,它会阻止您从int
获取{{1}}。
答案 11 :(得分:0)
试试这个。
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--;
}
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--;
}
答案 12 :(得分:0)
正确的方法是std::aligned_storage
。当您想要访问某个项目时,您必须手动构建和销毁项目以及reintrepret_cast
。我建议你在storage_t
周围编写一个小包装类来处理这个问题。有人提到使用boost::optional
使用bool和storage_t。这种方法可以为你节省一个布尔值。
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