私はしばらくc ++を使用していませんが、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.
コードを微調整しようとするとエラーメッセージが変化しますが、これらはこの特定のビルドからのエラーです。
助けてくれてありがとう
コンパイラエラーが発生する理由は次のとおりです。
T this_array[start_size];
この行により、Tarray
には実際にはT
のstart_size
インスタンスが含まれます。これらのインスタンスへのポインタや参照は保持されません。これらは、Tarrayの他のインスタンス変数を含む同じメモリブロックの一部になります。これにより、クラスのサイズがstart_sizeに依存するようになり、start_sizeはコンパイル時に認識されません。 C++クラスのサイズは、コンパイル時に知っている必要がありますが、これは不可能です。
これを解決するには2つの方法があります。
T
インスタンスの配列を割り当てます。これはstd::vector
が行うことです。このようなクラスを作成し、コピー/移動/展開などのときに正しく動作させるのは困難で面倒なので、代わりにstd::vector
を使用することをお勧めします。つまり:
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
を呼び出すことは不要であるだけでなく、ほぼ確実にクラッシュを引き起こします。
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];
}
};
次のコードは似たようなことをしますが、コンストラクターを使用しません。
#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;
実行時にアレイを作成する必要があります。
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にデフォルトのコンストラクター(つまり、引数をとらないコンストラクター)が必要であることに注意してください。
代わりにstd :: vectorを使用して、自分の生活をシンプルにしてください。 :)
(固定サイズの配列が必要な場合は、std :: arrayが可能かもしれません。そうでない場合は、C++ 11にあると思いますが、ブーストにはおそらく実装があります)。
ただし、ye-olde Cを使用しているかのように、通常の配列構文を使用する場合は、テンプレートパラメータを使用する必要があります。テンプレートクラスには2つの引数があります。1つはすでにある「T」用です。今、そして配列サイズのためのもう一つ。
その配列を自分で管理することで、人生を特に困難にしています。デストラクタを定義する必要があると感じた場合は、コンストラクタに加えてコピーコンストラクタを定義する必要があります。 (私が正しく思い出せば、これはビッグスリーのルールと呼ばれます)代わりに、RAIIに依存し、演算子deleteまたはdelete []を自分で明示的に呼び出す必要はありません。