如何声明其类没有默认构造函数的对象数组?

时间:2010-02-26 17:36:19

标签: c++ arrays

如果一个类只有一个带有一个参数的构造函数,那么如何声明一个数组?我知道在这种情况下推荐使用矢量。例如,如果我有一个班级

class Foo{

public:
Foo(int i) {}

}

如何声明包含10000个Foo对象的数组或向量?

13 个答案:

答案 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)

对于普通阵列,sbi有最好的答案,但没有给出一个例子。所以......

您应该使用新的展示位置:

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)

您必须使用聚合初始化程序,在{}

之间使用10000个个人初始化程序
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