C ++:数组的构造函数初始化器

我有一个大脑痉挛…如何在C ++中正确初始化一个对象数组?

非数组示例:

struct Foo { Foo(int x) { /* ... */ } }; struct Bar { Foo foo; Bar() : foo(4) {} }; 

数组示例:

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; // ??? I know the following syntax is wrong, but what's correct? Baz() : foo[0](4), foo[1](5), foo[2](6) {} }; 

编辑:疯狂的和疯狂的解决方法的想法是赞赏,但他们不会帮助我在我的情况。 我正在使用std :: vector和其他STL结构不可用的embedded式处理器,显而易见的解决方法是创build一个默认的构造函数,并且有一个可以在构build时调用的显式init()方法,这样我不必使用初始化器。 (这是我被Java final关键字+构造函数的灵活性所淹没的那些情况之一。)

不可能。 你需要一个数组成员的默认构造函数,它将被调用,之后,你可以在构造函数中进行任何初始化。

只是为了更新C ++ 11的这个问题,现在可以做到这一点,而且非常自然:

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; Baz() : foo{{4}, {5}, {6}} { } }; 

这些大括号也可以被简化为更简洁:

 struct Baz { Foo foo[3]; Baz() : foo{4, 5, 6} { } }; 

它也可以很容易地扩展到multidimensional array:

 struct Baz { Foo foo[3][2]; Baz() : foo{1, 2, 3, 4, 5, 6} { } }; 

现在,你不能使用数组成员的初始化列表。 你坚持这样做是困难的。

 class Baz { Foo foo[3]; Baz() { foo[0] = Foo(4); foo[1] = Foo(5); foo[2] = Foo(6); } }; 

在C ++ 0x中,你可以写:

 class Baz { Foo foo[3]; Baz() : foo({4, 5, 6}) {} }; 

不幸的是,没有办法直到C ++ 0x初始化数组成员。

您可以在构造函数体中使用std :: vector和push_back Foo实例。

你可以给Foo一个默认的构造函数(可能是私人的,使Baz成为朋友)。

您可以使用复制的数组对象(boost或std :: tr1)并从静态数组中初始化:

 #include <boost/array.hpp> struct Baz { boost::array<Foo, 3> foo; static boost::array<Foo, 3> initFoo; Baz() : foo(initFoo) { } }; boost::array<Foo, 3> Baz::initFoo = { 4, 5, 6 }; 

您可以将C ++ 0x auto关键字与模板专用化一起使用,例如名为boost::make_array()的函数(类似于make_pair() )。 对于N是1或2的参数,我们可以写variablesA

 namespace boost { /*! Construct Array from @p a. */ template <typename T> boost::array<T,1> make_array(const T & a) { return boost::array<T,2> ({{ a }}); } /*! Construct Array from @pa, @p b. */ template <typename T> boost::array<T,2> make_array(const T & a, const T & b) { return boost::array<T,2> ({{ a, b }}); } } 

变种B一样

 namespace boost { /*! Construct Array from @p a. */ template <typename T> boost::array<T,1> make_array(const T & a) { boost::array<T,1> x; x[0] = a; return x; } /*! Construct Array from @pa, @p b. */ template <typename T> boost::array<T,2> make_array(const T & a, const T & b) { boost::array<T,2> x; x[0] = a; x[1] = b; return x; } } 

具有-std=gnu++0x-O3 GCC-4.6生成完全相同的二进制代码

 auto x = boost::make_array(1,2); 

同时使用AB

 boost::array<int, 2> x = {{1,2}}; 

对于用户定义的types (UDT),虽然变体B会产生一个额外的拷贝构造函数 ,这通常会减慢速度,因此应该避免。

请注意, boost::make_array在使用显式字符数组文字进行调用时出现错误,如下例所示

 auto x = boost::make_array("a","b"); 

我相信这是一件好事,因为const char*文字在使用上可能是欺骗性的。

在4.5以后的GCC中可以使用的variables模板可以进一步使用,将每个N所有模板专用化锅炉代码boost::make_array()boost::make_array()定义的单个模板定义

 /*! Construct Array from @pa, @p b. */ template <typename T, typename ... R> boost::array<T,1+sizeof...(R)> make_array(T a, const R & ... b) { return boost::array<T,1+sizeof...(R)>({{ a, b... }}); } 

这与我们预期的非常相似。 第一个参数决定boost::array模板参数T ,所有其他参数都被转换成T 对于某些情况下,这可能是不可取的,但我不知道如果这是可以指定使用可变参数模板。

也许boost::make_array()应该进入Boost库?

在数组中创build对象时,只能调用默认的构造函数。

在特定情况下,当数组是该类的数据成员时, 不能在当前版本的语言中对其进行初始化。 这没有任何语法。 提供数组元素的默认构造函数或使用std::vector

独立数组可以用聚合初始值设定项初始化

 Foo foo[3] = { 4, 5, 6 }; 

但不幸的是没有相应的构造函数初始化列表的语法。

这似乎工作,但我不相信是正确的:

 #include <iostream> struct Foo { int x; Foo(int x): x(x) { } }; struct Baz { Foo foo[3]; static int bar[3]; // Hmm... Baz() : foo(bar) {} }; int Baz::bar[3] = {4, 5, 6}; int main() { Baz z; std::cout << z.foo[1].x << "\n"; } 

输出:

 $ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit g++ -pedantic arrayinit.cpp -o arrayinit 5 

买者自负。

编辑:不,科莫拒绝它。

另一个编辑:这是一种作弊,它只是推动成员的数组初始化到不同的地方。 所以它仍然需要Foo有一个默认的构造函数,但是如果你没有std::vector那么你可以为自己实现你需要的绝对最小值:

 #include <iostream> struct Foo { int x; Foo(int x): x(x) { }; Foo(){} }; // very stripped-down replacement for vector struct Three { Foo data[3]; Three(int d0, int d1, int d2) { data[0] = d0; data[1] = d1; data[2] = d2; } Foo &operator[](int idx) { return data[idx]; } const Foo &operator[](int idx) const { return data[idx]; } }; struct Baz { Three foo; static Three bar; // construct foo using the copy ctor of Three with bar as parameter. Baz() : foo(bar) {} // or get rid of "bar" entirely and do this Baz(bool) : foo(4,5,6) {} }; Three Baz::bar(4,5,6); int main() { Baz z; std::cout << z.foo[1].x << "\n"; } 

z.foo实际上并不是一个数组,但它看起来就像一个向量一样。 将begin()end()函数添加到Three是微不足道的。

在这个上下文中没有可以使用的数组构造语法,至less不是直接的。 你可以完成你正在尝试完成的事情:

 Bar::Bar() { static const int inits [] = {4,5,6}; static const size_t numInits = sizeof(inits)/sizeof(inits[0]); std::copy(&inits[0],&inits[numInits],foo); // be careful that there are enough slots in foo } 

…但是你需要给Foo一个默认的构造函数。

扭曲思维的想法:

 class mytwistedclass{ static std::vector<int> initVector; mytwistedclass() { //initialise with initVector[0] and then delete it :-) } }; 

现在将这个initVector设置为你想要实例化一个对象之前的东西。 然后你的对象用你的参数初始化。

你可以做到这一点,但不是很漂亮:

 #include <iostream> class A { int mvalue; public: A(int value) : mvalue(value) {} int value() { return mvalue; } }; class B { // TODO: hack that respects alignment of A.. maybe C++14's alignof? char _hack[sizeof(A[3])]; A* marr; public: B() : marr(reinterpret_cast<A*>(_hack)) { new (&marr[0]) A(5); new (&marr[1]) A(6); new (&marr[2]) A(7); } A* arr() { return marr; } }; int main(int argc, char** argv) { B b; A* arr = b.arr(); std::cout << arr[0].value() << " " << arr[1].value() << " " << arr[2].value() << "\n"; return 0; } 

如果你把它放在你的代码中,我希望你有一个非常好的理由。

这是我的解决scheme供您参考:

 struct Foo { Foo(){}//used to make compiler happy! Foo(int x){/*...*/} }; struct Bar { Foo foo[3]; Bar() { //initialize foo array here: for(int i=0;i<3;++i) { foo[i]=Foo(4+i); } } }; 

在Visual Studio 2012或以上版本,你可以这样做

 struct Foo { Foo(int x) { /* ... */ } }; struct Baz { Foo foo[3]; Baz() : foo() { } }; 
 class C { static const int myARRAY[10]; // only declaration !!! public: C(){} } const int C::myARRAY[10]={0,1,2,3,4,5,6,7,8,9}; // here is definition int main(void) { C myObj; }