71

我脑筋急转弯...如何在 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 构造不可用,显而易见的解决方法是创建一个默认构造函数并有一个init()可以在构造时间之后调用的显式方法,所以我不根本不必使用初始化程序。final(这是我被 Java 的关键字 + 构造函数的灵活性所宠坏的情况之一。)

4

14 回答 14

56

没有办法。您需要一个数组成员的默认构造函数,它将被调用,之后,您可以在构造函数中进行任何您想要的初始化。

于 2010-03-09T14:48:45.043 回答
40

只是为了更新 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} { }
};
于 2015-06-26T15:11:30.477 回答
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}) {}
};
于 2010-03-09T14:51:51.193 回答
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 };
于 2010-03-09T15:46:50.223 回答
3

您可以将C++0x auto关键字与模板特化一起用于例如名为boost::make_array()(类似于make_pair())的函数。对于 whereN是 1 或 2 个参数的情况,我们可以将变体 A写为

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 }});
}
}

变体 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 @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;
}
}

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

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

像使用AB一样

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

但是,对于用户定义类型(UDT),变体 B 会导致额外的复制构造函数,这通常会减慢速度,因此应该避免。

请注意,boost::make_array使用显式 char 数组文字调用它时会出错,如下例所示

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

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

可变参数模板,自 4.5 起在 GCC 中可用,可进一步用于将每个模板的所有模板专业化样板代码简化为定义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::make_array()应该进入 Boost 库?

于 2011-06-15T11:29:01.983 回答
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 是微不足道的。

于 2010-03-09T14:56:05.310 回答
1

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

于 2010-03-09T14:51:15.037 回答
1

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

可以使用聚合初始化器初始化独立数组

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

但不幸的是,构造函数初始值设定项列表没有相应的语法。

于 2010-03-09T14:51:57.777 回答
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 一个默认的构造函数。

于 2010-03-09T14:56:03.313 回答
0

来自扭曲心灵的想法:

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

};

现在将其设置initVector为您在实例化对象之前想要的东西。然后使用您的参数初始化您的对象。

于 2010-03-09T15:05:03.817 回答
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;
}

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

于 2016-02-29T17:23:44.143 回答
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);
        }
    }
};
于 2017-05-05T06:47:06.120 回答
-1

在 Visual Studio 2012 或更高版本中,你可以这样做

struct Foo { Foo(int x) { /* ... */  } };

struct Baz { 
     Foo foo[3];

     Baz() : foo() { }
};
于 2016-01-13T07:56:05.830 回答
-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;
   }
于 2013-06-10T18:43:09.887 回答