【问题标题】:C++ Initializing Non-Static Member ArrayC++ 初始化非静态成员数组
【发布时间】:2011-08-04 09:00:15
【问题描述】:

我正在编辑一些使用如下定义的全局数组的旧 C++ 代码:

int posLShd[5] = {250, 330, 512, 600, 680};
int posLArm[5] = {760, 635, 512, 320, 265};
int posRShd[5] = {765, 610, 512, 440, 380};
int posRArm[5] = {260, 385, 512, 690, 750};
int posNeck[5] = {615, 565, 512, 465, 415};
int posHead[5] = {655, 565, 512, 420, 370};

我想让所有这些数组成为下面定义的 Robot 类的私有成员。但是,C++ 编译器不允许我在声明数据成员时对其进行初始化。

class Robot
{
   private:
       int posLShd[5];
       int posLArm[5];
       int posRShd[5];
       int posRArm[5];
       int posNeck[5];
       int posHead[5];
   public:
       Robot();
       ~Robot();
};

Robot::Robot()
{
   // initialize arrays
}

我想在 Robot() 构造函数中初始化这六个数组的元素。除了一个一个地分配每个元素之外,还有什么方法可以做到这一点?

【问题讨论】:

  • 最简单的方法是让它们成为静态成员,因为它们以前是全局成员,但是,这与原始问题不同。

标签: c++ arrays default-constructor


【解决方案1】:

如果您的要求确实允许,那么您可以将这 5 个数组作为您的类的 static 数据成员,并在 .cpp 文件中定义时初始化它们,如下所示:

class Robot
{
  static int posLShd[5];
  //...
};
int Robot::posLShd[5] = {250, 330, 512, 600, 680}; // in .cpp file

如果这不可能,那么像往常一样用不同的名称声明这个数组,并在构造函数中使用memcpy() 作为数据成员。

编辑: 对于非静态成员,可以使用低于template 的样式(对于任何类型,如int)。要更改大小,只需同样重载元素数量:

template<size_t SIZE, typename T, T _0, T _1, T _2, T _3, T _4>
struct Array
{
  Array (T (&a)[SIZE])
  {
    a[0] = _0;
    a[1] = _1;
    a[2] = _2;
    a[3] = _3;
    a[4] = _4;
  }
};

struct Robot
{
  int posLShd[5];
  int posLArm[5];
  Robot()
  {
    Array<5,int,250,330,512,600,680> o1(posLShd);
    Array<5,int,760,635,512,320,265> o2(posLArm);
  }
};

C++11

数组初始化现在变得微不足道了:

class Robot
{
   private:
       int posLShd[5];
       ...
   public:
       Robot() : posLShd{0, 1, 2, 3, 4}, ...
       {}
};

【讨论】:

  • 这个答案最好的部分在最后,就像编辑过的老式答案一样。
【解决方案2】:

您可以将其设为静态,也可以使用 C++0x 中引入的新初始化

class Robot
{
private:
  int posLShd[5];
  static int posLArm[5];
  // ...
public:
  Robot() :
    posLShd{250, 330, 512, 600, 680} // only C++0x                                                                                     
  {}

  ~Robot();
};

int Robot::posLArm[5] = {760, 635, 512, 320, 265};

【讨论】:

    【解决方案3】:

    将另一种方法加入其中(一种 告诉您像大多数其他答案一样让数组数据成员 static - 我假设 知道它们是否应该是static),这是我使用的零开销方法:制作static 成员函数并让它们返回std::array&lt;&gt;(或boost::array&lt;&gt;,如果你的编译器太旧,无法附带std::std::tr1:: 实现):

    class Robot
    {
        static std::array<int, 5> posLShd_impl() { std::array<int, 5> x = {{ 250, 330, 512, 600, 680 }}; return x; }
        static std::array<int, 5> posLArm_impl() { std::array<int, 5> x = {{ 760, 635, 512, 320, 265 }}; return x; }
        static std::array<int, 5> posRShd_impl() { std::array<int, 5> x = {{ 765, 610, 512, 440, 380 }}; return x; }
        static std::array<int, 5> posRArm_impl() { std::array<int, 5> x = {{ 260, 385, 512, 690, 750 }}; return x; }
        static std::array<int, 5> posNeck_impl() { std::array<int, 5> x = {{ 615, 565, 512, 465, 415 }}; return x; }
        static std::array<int, 5> posHead_impl() { std::array<int, 5> x = {{ 655, 565, 512, 420, 370 }}; return x; }
    
        std::array<int, 5> posLShd;
        std::array<int, 5> posLArm;
        std::array<int, 5> posRShd;
        std::array<int, 5> posRArm;
        std::array<int, 5> posNeck;
        std::array<int, 5> posHead;
    public:
        Robot();
    };
    
    Robot::Robot()
      : posLShd(posLShd_impl()),
        posLArm(posLArm_impl()),
        posRAhd(posRAhd_impl()),
        posRArm(posRArm_impl()),
        posNeck(posNeck_impl()),
        posHead(posHead_impl())
    { }
    

    【讨论】:

    • 这真的是0开销吗?看起来静态函数每次都必须复制整个数组,而不是就地初始化数组元素。也许我误解了 C++ 中的初始化?
    • @weberc2 : NRVO 使这在实践中不是问题。
    【解决方案4】:

    除了一个一个地分配每个元素之外,还有其他方法吗?

    如果你想用一些默认值填充数组的所有元素,可以使用std::fill

    #include <algorithm>
    
    // ...
    Robot::Robot()
    {
        std::fill(posLShd, posLShd+5, 13 ) ; // 13 as the default value
    
        // Similarly work on with other arrays too.
    }
    

    如果数组的每个元素都需要填充不同的值,那么在每个索引处赋值是唯一的选择。

    【讨论】:

      【解决方案5】:

      将全局变量保留在代码中,然后使用 memcpy() 初始化本地数组,将全局数组的内容复制到本地数组。

      【讨论】:

        【解决方案6】:

        这与当前问题仅略有相关,但它是一个完全解决 duplicate 的特殊情况。

        零初始化是 C++ 语言中数组的一种特殊情况。如果初始化列表比数组短,则其余元素初始化为零。例如,重复问题的要求是对类的所有成员进行零初始化,包括构造函数中最后一个数组的所有元素:

        class myprogram {
        public:
            myprogram ();
        private:
            double aa,bb,cc;
            double G_[2000];
        };
        

        这对于构造函数的定义就足够了:

        myprogram::myprogram():aa(0.0),bb(0.0),cc(0.0), G_{0.} {}
        

        因为G_ 的第一个元素被显式初始化为值0.,而所有其他元素都初始化为零。

        【讨论】:

          【解决方案7】:
          // class definition with incomplete static member could be in a header file
          Class Robot {
              static const int posLShd[5];
          ....
          // this needs to be placed in a single translation unit only
          const int Robot::posLShd[5] = {250, 330, 512, 600, 680};
          

          【讨论】:

            【解决方案8】:

            并非如此,尽管我同意 stefaanv 的评论 - 如果它们以前是全局的,那么将它们设为静态将使您获得“简单的分配”,并且它们看起来好像它们可能是 const static。

            如果这些值是您偶尔更改的,您可以考虑在创建类时从外部文件中读取它们,这样可以避免重新编译。

            您也可以考虑使用 std::vector 来代替它提供的某些功能的固定数组。

            【讨论】:

              【解决方案9】:

              我在这里遗漏了什么吗?下面的代码有效。只需声明成员,并立即初始化。

              #include <iostream>
              
              class Robot {
                public:
                int posLShd[5] = {250, 330, 512, 600, 680};
                int posLArm[5] = {760, 635, 512, 320, 265};
                int posRShd[5] = {765, 610, 512, 440, 380};
                int posRArm[5] = {260, 385, 512, 690, 750};
                int posNeck[5] = {615, 565, 512, 465, 415};
                int posHead[5] = {655, 565, 512, 420, 370};
                public:
                  Robot() {}
                  ~Robot() {}
              };
              
              int main () {
                Robot obj;
                for (int i = 0;i < 5;i++) {
                  std::cout << obj.posRArm[i] << std::endl;
                }
              }
              

              【讨论】:

              • 它不起作用,编译器错误是:a brace-enclosed initializer is not allowed here ...。即使它有效,它也不是很有用。我不会将真实/科学数据放入已定义类的头文件中。我也会犹豫只输入数据来指定一些元素。在构造函数初始化列表中这样做是不同的——您可以拥有各种用于初始化的数据集,您可以选择运行时间,例如允许丰富的设置管理。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-04-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-05-18
              • 1970-01-01
              相关资源
              最近更新 更多