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