Как использовать boost :: array с неизвестным размером в качестве переменной объекта

17

Я хотел бы использовать boost :: array как член класса, но я не знаю его размер во время компиляции. Я думал о чем-то подобном, но это не работает:

int main() {
    boost::array<int, 4> array = {{1,2,3,4}};
    MyClass obj(array);
}

class MyClass {
    private:
        boost::array<int, std::size_t> array;
    public:
        template<std::size_t N> MyClass(boost::array<int, N> array)
        : array(array) {};
};

В компиляторе gcc говорится:

error: type/value mismatch at argument 2 in template parameter list for
  ‘template<class _Tp, long unsigned int _Nm> struct boost::array’
error:   expected a constant of type ‘long unsigned int’, got ‘size_t’

Это, очевидно, означает, что в качестве членов класса нельзя использовать массивы переменного размера. Если это так, это отрицает все преимущества boost :: array над векторами или стандартными массивами.

Можете ли вы показать мне, что я сделал не так?

    
задан Michael Kowhan 09.01.2010 в 02:27
источник

7 ответов

19

Массив Boost имеет фиксированный размер на основе второго параметра шаблона, а boost::array<int,4> - это другой тип из boost::array<int,2> . Вы не можете иметь экземпляры одного класса (MyClass в вашем примере), которые имеют разные типы для своих членов.

Однако, std :: векторы могут иметь разные размеры без разных типов:

struct MyClass {
  template<std::size_t N>
  explicit
  MyClass(boost::array<int, N> const& array)
  : data(array.begin(), array.end())
  {}

private:
  std::vector<int> data;
};

int main() {
  boost::array<int, 4> a = {{1,2,3,4}};
  MyClass obj(a);

  boost::array<int, 2> a2 = {{42,3}};
  MyClass obj2(a2);

  // notice obj.data.size() != obj2.data.size()

  return 0;
}

Тем не менее, boost :: array по-прежнему полезен (это даже полезно в этом примере кода), просто не так, как вы хотите его использовать.

    
ответ дан Roger Pate 09.01.2010 в 03:27
источник
12

Вам не хватает некоторых основных моментов. Вы можете:

  1. A статически выделенный массив - char arr[10];
  2. A динамически выделенный массив - char* arr = new arr[10];

Первый размер известен во время компиляции (потому что размер является константой ), поэтому вы можете предварительно выделить для него пространство памяти, а другое - нет, поэтому вам нужно выделить памяти для него во время выполнения.

STL / TR1 / Boost предоставляет обертки для обоих типов массивов. Это не только обертки для convieniece, но и для безопасности (проверка диапазона в некоторых ситуациях) и мощности (итераторы). Для обоих случаев у нас есть отдельная оболочка:

  1. Статически распределенная обертка массива boost::array<char,10> arr;
  2. Динамически распределенная обертка массива std::vector<char> arr;

Последнее имеет преимущество самостоятельного изменения размера и позволяет изменять размер в дополнение к динамически распределяемому. boost::array , с другой стороны, имитирует конструкцию type arr[const] .

Следовательно, вам нужно решить, хотите ли вы, чтобы класс имел статически выделенную память или динамически. Первое, имеет смысл только в том случае, если хранение классов является либо фиксированным, либо одним из нескольких фиксированных размеров. Последнее имеет смысл во всех остальных случаях.

Статически выделенные будут использовать шаблоны

template < size_t N >
class MyClass {
private:
    boost::array< int, N > array;
public:
   MyClass(boost::array< int, N > array) : array(array) {};
};

// ...

boost::array<int, 4> array = {{1,2,3,4}};
MyClass<4> obj(array);

Но создаст отдельный код для каждого размера класса, и они не будут взаимодействовать (это можно обойти, хотя).

Динамически выделенные будут использовать векторы

class MyClass {
private:
    std::vector< int > array;
public:
   MyClass(const std::vector< int >& array) : array(array) {};
};

Не бойтесь векторов, рассматривайте их как динамически распределенные массивы - изменение размеров векторов является дополнительным преимуществом, которое практически не влияет на производительность.

    
ответ дан Kornel Kisielewicz 09.01.2010 в 07:48
источник
5

Могу ли я предложить вместо этого использовать boost :: scoped_array ? С другой стороны, вы можете не захотеть на самом деле копировать весь массив каждый раз. Тогда boost :: shared_array будет лучшим выбором.

    
ответ дан Nikolai Fetissov 09.01.2010 в 03:47
источник
3

Нет, boost :: array (он находится в TR1 как std :: tr1 :: array) - это буфер статического размера. Точка класса заключается в том, чтобы избежать динамического распределения памяти - вы можете полностью поставить boost :: array в стек.

Вы можете заставить свой класс example взять шаблон int и передать его члену boost :: array,

template<int Size>
class MyClass
{
private:
    boost::array<int, Size> m_array;
public:
    // ....
};

Но это просто одевание, это все еще статическое распределение.

    
ответ дан Terry Mahaffey 09.01.2010 в 02:35
источник
1

Вы ошибаетесь в отношении ошибки:

    template<unsigned long N> MyClass(boost::array<int, N> array) : array(array) {};

Должен работать. Кстати, это все равно будет генерировать массив во время компиляции, поэтому это нехорошее решение. И другие ошибки будут возникать.

Здесь вам нужен вектор с зарезервированным размером и некоторыми утверждениями, которые сохраняют емкость с фиксированным размером.

    
ответ дан Klaim 09.01.2010 в 02:33
источник
1

Хотя вы уже приняли ответ, обратите внимание, что std :: vector может не быть правильным выбором для вашей задачи. Если вы хотите создать массив один раз - массив с фиксированным размером - и вы не хотите его изменять позже, тогда хороший старый простой массив может быть правильным выбором для тебя! Игнорировать boost :: array, игнорировать std :: vector, его намерения очень разные, прост. KISS, YAGNI и т. Д. ...

int main() {
    int* array = new int[4];
    for( int i=0; i<4; ++i ) array[i] = i+1;
    MyClass obj(array);
}

class MyClass {
    private:
        int* array;
    public:
        MyClass( int* array )
        : array(array) {}
        ~MyClass() { delete[] array; }
};

РЕДАКТИРОВАТЬ: Как уже заявил Николай Н. Фетисов, boost :: scoped_array может быть хорошим выбором. Он предоставляет тонкую оболочку RAII вокруг массива. Вот пример использования (надеюсь, что это правильно, не стесняйтесь редактировать в противном случае):

class MyClass {
    private:
        boost::scoped_array<int> array;
    public:
        MyClass( int* array )
        : array(array) {}
};
    
ответ дан Frunsi 09.01.2010 в 03:59
источник
0

Если вам не требуется динамическое изменение размера, вам не нужен std :: vector

просто функция accept * int

MyFunction (int* array,int size); // function prototype

и передайте ему указатель .data () boost :: array.)

boost::array<int,4> testArray;
boost::array<int,5> testArray2;

// Calling the function:
MyFunction(testArray.data(),4);
MyFunction(testArray2.data(),5);

ключ является .data () людьми !!! Если вы хотите увеличить массивы для замены обычных массивов, это, пожалуй, способ (без использования шаблонов и всего этого)

    
ответ дан Mike Gao 02.09.2013 в 15:38
источник