C++ Инициализация нестатического массива элементов

Я работаю над редактированием старого кода 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(). Есть ли способ сделать это, кроме как назначать каждый элемент один за другим?


person Michael Hornfeck    schedule 13.04.2011    source источник
comment
Проще всего было бы сделать их статическими членами, потому что раньше они были глобальными, однако это не так, как в исходном вопросе.   -  person stefaanv    schedule 13.04.2011


Ответы (8)


Если ваше требование действительно позволяет, вы можете сделать эти 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}, ...
       {}
};
person iammilind    schedule 13.04.2011

вы можете сделать его статическим или использовать новую инициализацию, представленную в 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};
person andreabedini    schedule 13.04.2011

Чтобы добавить еще один подход (и тот, который не говорит вам сделать элементы данных массива static, как большинство других ответов, я предполагаю, что вы знаете ли или не должны быть static), вот подход с нулевыми издержками, который я использую: создайте static функций-членов и заставьте их возвращать std::array<> (или boost::array<>, если ваш компилятор слишком стар для реализации 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())
{ }
person ildjarn    schedule 13.04.2011
comment
Это действительно 0 накладных расходов? Похоже, что статическим функциям придется каждый раз копировать весь массив, а не инициализировать элементы массива на месте. Может быть, я неправильно понимаю инициализацию в C++? - person weberc2; 23.06.2014
comment
@weberc2 : NRVO на практике это не проблема. - person ildjarn; 23.06.2014

Есть ли способ сделать это, кроме как назначать каждый элемент один за другим?

Если вы хотите заполнить все элементы массива некоторыми значениями по умолчанию, можно использовать std::fill.

#include <algorithm>

// ...
Robot::Robot()
{
    std::fill(posLShd, posLShd+5, 13 ) ; // 13 as the default value

    // Similarly work on with other arrays too.
}

Если каждый элемент массива должен быть заполнен другим значением, то единственным вариантом является присвоение значения каждому индексу.

person Mahesh    schedule 13.04.2011

Оставьте глобальные массивы в коде, а затем инициализируйте локальные массивы с помощью memcpy(), скопировав содержимое глобальных массивов в локальные.

person Antti Huima    schedule 13.04.2011

Это лишь немного связано с настоящим вопросом, но это особый случай, который полностью касается дубликата.

Нулевая инициализация — это особый случай для массивов в языке 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., а все остальные элементы инициализируются нулем.

person Serge Ballesta    schedule 14.01.2020

Не совсем, хотя я согласен с комментарием stefaanv - если бы они были глобальными ранее, то сделав их статическими, вы получили бы «легкое назначение», и с первого взгляда кажется, что они могут быть постоянными статическими.

Если вы время от времени меняете эти значения, вы можете прочитать их из внешнего файла при создании класса, чтобы избежать перекомпиляции.

Вы также можете рассмотреть возможность использования std::vector вместо фиксированных массивов для некоторых функций, которые он предоставляет.

person holtavolt    schedule 13.04.2011

Я что-то упустил здесь? Код ниже работает. Просто объявите членов и сразу инициализируйте.

#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;
  }
}
person eigenfield    schedule 06.11.2018
comment
Это не работает, и ошибка компилятора: a brace-enclosed initializer is not allowed here .... Даже если это сработало, это не очень полезно. Я бы не помещал реальные/научные данные в заголовочный файл, где был определен класс. Я бы также не решился указать ряд элементов, введя только данные. Выполнение этого в списке инициализации конструктора отличается - у вас может быть множество наборов данных для инициализации, которые вы можете выбрать во время выполнения, что позволяет, например, управлять богатыми настройками. - person OpalApps; 04.04.2019