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);
同时使用A和B
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; }