我有大脑痉挛...如何在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) {}
};
编辑:Wild&我们非常感谢疯狂的解决方法,但在我的案例中,它们对我没有帮助。我正在开发一个嵌入式处理器,其中std :: vector和其他STL结构不可用,显而易见的解决方法是创建一个默认构造函数,并且有一个可以在构造时间之后调用的显式init()
方法,所以我根本不必使用初始化器。 (这是我已经被Java的final
关键字+构造函数的灵活性所破坏的情况之一。)
答案 0 :(得分:49)
没有办法。您需要一个数组成员的默认构造函数,然后调用它,之后,您可以在构造函数中进行任何初始化。
答案 1 :(得分:33)
为了更新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} { }
};
也可以很容易地扩展到多维数组:
struct Baz {
Foo foo[3][2];
Baz() : foo{1, 2, 3, 4, 5, 6} { }
};
答案 2 :(得分:16)
目前,您无法将初始化程序列表用于数组成员。你很难坚持下去。
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}) {}
};
答案 3 :(得分:7)
不幸的是,没有办法初始化数组成员直到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 };
答案 4 :(得分:3)
您可以将 C ++ 0x auto
关键字与模板专精化一起使用,例如名为boost::make_array()
的函数(类似于{{ 1}})。对于make_pair()
是1或2个参数的情况,我们可以将变体A 写为
N
和变体B 为
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 @p a, @p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
return boost::array<T,2> ({{ a, b }});
}
}
GCC-4.6与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 @p a, @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
同时使用 A 和 B
auto x = boost::make_array(1,2);
对于用户定义的类型(UDT),变体B会导致一个额外的复制构造函数,这通常会减慢速度,因此应该避免使用。
请注意,使用显式char数组文字调用时会出现boost::array<int, 2> x = {{1,2}};
错误,如下例所示
boost::make_array
我认为这是一件好事,因为auto x = boost::make_array("a","b");
文字在使用时可能具有欺骗性。
Variadic模板 ,自4.5以来在GCC中可用,可以进一步使用将每个const char*
的所有模板专业化样板代码减少为 N
的单个模板定义定义为
boost::make_array()
这非常符合我们的预期。第一个参数确定/*! Construct Array from @p a, @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 Libraries?
答案 5 :(得分:2)
这似乎有效,但我不相信它是对的:
#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
警告经理。
编辑:不,Comeau拒绝它。
另一个编辑:这是一种作弊,它只是将逐个成员的数组初始化推送到另一个地方。所以它仍然需要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是微不足道的。
答案 6 :(得分:1)
在数组中创建对象时,只能调用默认构造函数。
答案 7 :(得分:1)
在特定情况下,当数组是类的数据成员时,无法在当前版本的语言中初始化它。这没有语法。为数组元素提供默认构造函数或使用std::vector
。
可以使用聚合初始化程序
初始化独立数组Foo foo[3] = { 4, 5, 6 };
但遗憾的是构造函数初始化列表没有相应的语法。
答案 8 :(得分:0)
没有可在此上下文中使用的数组构造语法,至少不能直接使用。你可以通过以下方式完成你想要完成的任务:
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一个默认的构造函数。
答案 9 :(得分:0)
来自扭曲思想的想法:
class mytwistedclass{
static std::vector<int> initVector;
mytwistedclass()
{
//initialise with initVector[0] and then delete it :-)
}
};
现在在实例化对象之前将此initVector
设置为您想要的内容。然后使用您的参数初始化您的对象。
答案 10 :(得分:0)
你可以做到,但它并不漂亮:
#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;
}
如果你把它放在你的代码中,我希望你有一个很好的理由。
答案 11 :(得分:0)
这是我的解决方案供您参考:
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);
}
}
};
答案 12 :(得分:-1)
在visual studio 2012或更高版本中,您可以这样做
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
Baz() : foo() { }
};
答案 13 :(得分:-2)
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;
}