Объявление массива внутри класса и установка его размера с помощью конструктора - PullRequest
7 голосов
/ 05 марта 2012

Я давно не работал с c ++, но я только начал проект с ним. Это может быть невозможно, но я пытаюсь создать шаблонный класс с массивом, который устанавливает его размер равным значению константы, которую я пытаюсь установить с помощью конструктора.

Это код конструктора:

Tarray(int s): start_size(s){
    }

Это код, который устанавливает размер массива:

const int start_size;
T this_array[start_size];

Это весь файл:

#ifndef TARRAY_H_
#define TARRAY_H_


template<typename T>
class Tarray {
private:
    const int start_size;
    T this_array[start_size];
    int array_size;
public:
    Tarray(int s): start_size(s){
    }
    ~Tarray(){
        delete[] this_array;
    }
    T & operator[](int i){
        return this_array[i];
    }
};



#endif /* TARRAY_H_ */

Вот ошибки, которые я получаю:

..\/template_array/Tarray.h:16:24: error: 'Tarray<T>::start_size' cannot appear in a constant-expression
..\/template_array/Tarray.h:16:34: error: 'new' cannot appear in a constant-expression
..\/template_array/Tarray.h:16:34: error: ISO C++ forbids initialization of member 'this_array' [-fpermissive]
..\/template_array/Tarray.h:16:34: error: making 'this_array' static [-fpermissive]
..\/template_array/Tarray.h: In instantiation of 'Tarray<Person>':
..\Human.cpp:17:24:   instantiated from here
..\/template_array/Tarray.h:16:34: error: invalid in-class initialization of static data member of non-integral type 'Person*'
Build error occurred, build is stopped
Time consumed: 343  ms. 

Сообщения об ошибках менялись, когда я пытаюсь настроить код, но это ошибки этой конкретной сборки.

Спасибо за любую помощь

Ответы [ 5 ]

10 голосов
/ 05 марта 2012

Причина, по которой вы получаете ошибки компилятора, заключается в следующей строке:

T this_array[start_size];

Эта строка заставит ваши Tarray фактически содержать start_size экземпляров T. Он не будет содержать указатель или ссылку на эти экземпляры - они будут частью того же блока памяти, который содержит другие переменные экземпляра Tarray. Это сделало бы размер класса зависимым от start_size, а start_size не известен во время компиляции. Размер любого класса C ++ должен быть известен во время компиляции, это невозможно.

Есть два способа решить эту проблему:

  1. Выделите массив T экземпляров в куче, используя массив new. Это то, что делает std::vector. Написать такой класс и заставить его вести себя правильно, когда он копируется / перемещается / расширяется / и т. Д., Сложно и утомительно, поэтому я рекомендую использовать вместо него std::vector.
  2. Установить фиксированное количество экземпляров T и передать его в качестве параметра шаблона

т.е:.

template<typename T, std::size_t N>
class TArray
{
    ...
    T this_array[N];
    ...
}

Это то, что делают std :: array (только C ++ 11) и boost :: array. Опять же, я бы рекомендовал использовать один из них вместо того, чтобы писать свой. Если, конечно, это не домашнее задание ...

Наконец, стоит отметить, что это ошибка:

~Tarray(){
    delete[] this_array;
}

this_array не был выделен с new, поэтому вы не должны delete его. Если массив является частью класса в том виде, как он есть здесь (вместо того, чтобы выделяться в куче и принадлежать классу отдельно), то он будет уничтожен вместе с остальной частью класса по умолчанию. Вызов delete не только не нужен, но почти наверняка вызовет сбой.

2 голосов
/ 05 марта 2012

Следующий код делает нечто подобное, но не использует конструктор:

#ifndef TARRAY_H_ 
#define TARRAY_H_ 


template<int SizeT> 
class Tarray { 
private: 
    T this_array[SizeT]; 
public: 
    Tarray() {} 
    ~Tarray() {} 
    T & operator[](int i){ 
        return this_array[i]; 
    } 
}; 

#endif /* TARRAY_H_ */ 

, и вы можете использовать его следующим образом:

TArray<10> myArray;
2 голосов
/ 05 марта 2012

std::vector как раз инструмент для этой работы:

template<typename T>
class Tarray {
private:
    std::vector<T> this_array;
public:
    Tarray(int s): this_array(s){
    }
    ~Tarray(){
    }
    T & operator[](int i){
        return this_array[i];
    }
};
1 голос
/ 05 марта 2012

Вы должны создать массив во время выполнения.

template<typename T>
class Tarray {
private:
    const int start_size;
    T* this_array;
    int array_size;

    Tarray( const Tarrat& inObj ); // no copy

public:
    Tarray(int s): start_size(s), this_array( new T[s] ) {
    }
    ~Tarray(){
        delete[] this_array;
    }
    T & operator[](int i){
        return this_array[i];
    }
};

Обратите внимание, чтобы это работало, T должен иметь конструктор по умолчанию (то есть конструктор, который не принимает аргументов).

0 голосов
/ 05 марта 2012

Используйте вместо этого std :: vector и упростите себе жизнь.:)

(Если вам нужен массив фиксированного размера, тогда возможно использование std :: array, я думаю, что это в C ++ 11, если нет, то boost, вероятно, имеет реализацию).

Если вы настаиваете на том, чтобы использовать этот обычный синтаксис массива, хотя, как если бы вы использовали ye-olde C, тогда вам нужно будет использовать параметр шаблона, такой, чтобы у вашего шаблона был два аргумента - один для 'T«он уже есть, и еще один для размера массива.

Вы сами усложняете жизнь, управляя этим массивом самостоятельно - если вы чувствуете, что должны определить деструктор, вам действительно следует определить конструктор копирования в дополнение».конструктору.(Это называется Правило Большой Тройки, если я правильно помню), вместо этого полагайтесь на RAII и избегайте необходимости когда-либо явно вызывать оператор delete или delete [] самостоятельно.

...