Я хотел бы использовать повышение:: выстройте как участник класса, но я не знаю размера во время компиляции. Я думал о чем-то вроде этого, но это не работает:
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 имеет фиксированный размер на основе второго параметра шаблона, а []boost::array
] представляет собой []отличный от [] тип[]boost::array
]. Вы не можете иметь экземпляры одного и того же класса (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::массив все равно полезен (он даже полезен в данном примере кода), просто не в том виде, в котором Вы хотите его использовать.[
].] Вы упускаете некоторые основные моменты. Ты можешь: [
] []char arr[10];[
][]char* arr = новый arr[10]; [
][]Размер первого известен во время компиляции (так как он равен []константе[]), поэтому можно предварительно выделить для него место в памяти, а второго нет, поэтому необходимо выделить для него память во время выполнения. [
] []STL/TR1/Boost предоставляет []обёртки[] для обоих типов массивов. Это обмотчики не только для convieniece, но и для безопасности (проверка диапазона в некоторых ситуациях) и питания (итераторы). Для обоих случаев у нас есть отдельная обёртка:[
] []boost::array arr;[
][]std::vector arr;[
][]Последняя имеет преимущество самообёртывания и позволяет не только динамически выделять массивы, но и изменять их размер. С другой стороны []boost::array[
] имитирует конструкцию типа []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) {};
};
]
[]Не бойтесь векторов, относитесь к ним как к динамически выделенным массивам - изменение размеров векторов является дополнительным преимуществом, которое практически не влияет на производительность.[
].] Могу ли я предложить вместо этого использовать [] boost::scoped_array[]? С другой стороны, вы, возможно, не захотите на самом деле каждый раз []копировать [] весь массив. Тогда []boost::shared_array[] был бы лучшим выбором.[
].]Нет, массив boost::(в TR1 он в виде массива std::tr1::) является буфером статического размера. Смысл класса заключается в том, чтобы избежать динамического выделения памяти - массив boost::можно поместить полностью на стек. [
] []Можно заставить ваш пример класса взять шаблонный int и передать его члену массива boost::,[
] [template<int Size>
class MyClass
{
private:
boost::array<int, Size> m_array;
public:
// ....
};
]
[]Но это всего лишь перевязка, это все равно статическое выделение.[
]] Вы ошибаетесь насчет ошибки :[
] [ template<unsigned long N> MyClass(boost::array<int, N> array) : array(array) {};
]
[] Должно сработать. Кстати, при компиляции массив все равно будет генерироваться, так что это не лучшее решение. И возникнут другие ошибки.[
] []Здесь Вам нужен вектор, с зарезервированным размером и некоторыми утверждениями, которые сохраняют емкость на фиксированном размере.[
].] Хотя вы уже приняли ответ, обратите внимание, что 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; }
};
]
[][]EDIT:[] Как уже говорил Николай N Фетиссов, boost::scoped_array может быть хорошим выбором. Он обеспечивает тонкую обертку RAII вокруг массива. Вот пример использования (надеюсь, он правильный, не стесняйтесь редактировать иначе):[
] [class MyClass {
private:
boost::scoped_array<int> array;
public:
MyClass( int* array )
: array(array) {}
};
]