Подтвердить что ты не робот

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

Я хотел бы использовать 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 над векторами или стандартными массивами.

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

  • Статически выделенная обертка массива boost::array<char,10> arr;
  • Динамически распределенная оболочка массива 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) {};
};

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

Ответ 3

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

Ответ 4

Нет, 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:
    // ....
};

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

Ответ 5

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

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

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

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

Ответ 6

Хотя вы уже приняли ответ, обратите внимание, что std::vector может не быть правильным выбором для вашей задачи. Если вы хотите создать массив один раз - массив с фиксированным размером - и вы не хотите его изменять позже, тогда хороший старый простой массив может быть правильным выбором для тебя! Игнорировать boost:: array, ignore 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; }
};

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

class MyClass {
    private:
        boost::scoped_array<int> array;
    public:
        MyClass( int* array )
        : array(array) {}
};

Ответ 7

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

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

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

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

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

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

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