Как использовать повышение:: массив с неизвестным размером как переменная объекта

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

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’

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

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

17
задан Michael Kowhan 9 January 2010 в 02:38
поделиться

6 ответов

[

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

].
19
ответ дан 30 November 2019 в 11:17
поделиться
[

] Вы упускаете некоторые основные моменты. Ты можешь: [

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

]Размер первого известен во время компиляции (так как он равен []константе[]), поэтому можно предварительно выделить для него место в памяти, а второго нет, поэтому необходимо выделить для него память во время выполнения. [

] [

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

] [
    ] [
  1. ]Статически выделенная обёртка для массивов []boost::array arr;[][
  2. ] [
  3. ]Динамически выделенная обёртка для массивов []std::vector arr;[][
  4. ] [
] [

]Последняя имеет преимущество самообёртывания и позволяет не только динамически выделять массивы, но и изменять их размер. С другой стороны []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) {};
};
] [

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

].
12
ответ дан 30 November 2019 в 11:17
поделиться
[

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

].
6
ответ дан 30 November 2019 в 11:17
поделиться
[

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

] [

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

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

]Но это всего лишь перевязка, это все равно статическое выделение.[

]
3
ответ дан 30 November 2019 в 11:17
поделиться
[

] Вы ошибаетесь насчет ошибки :[

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

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

] [

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

].
1
ответ дан 30 November 2019 в 11:17
поделиться
[

] Хотя вы уже приняли ответ, обратите внимание, что 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) {}
};
]
1
ответ дан 30 November 2019 в 11:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: