web-dev-qa-db-ja.com

クラス内で配列を宣言し、コンストラクターでそのサイズを設定する

私はしばらく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. 

コードを微調整しようとするとエラーメッセージが変化しますが、これらはこの特定のビルドからのエラーです。

助けてくれてありがとう

7
sinθ

コンパイラエラーが発生する理由は次のとおりです。

T this_array[start_size];

この行により、Tarrayには実際にはTstart_sizeインスタンスが含まれます。これらのインスタンスへのポインタや参照は保持されません。これらは、Tarrayの他のインスタンス変数を含む同じメモリブロックの一部になります。これにより、クラスのサイズがstart_sizeに依存するようになり、start_sizeはコンパイル時に認識されません。 C++クラスのサイズは、コンパイル時に知っている必要がありますが、これは不可能です。

これを解決するには2つの方法があります。

  1. Array newを使用して、ヒープ上のTインスタンスの配列を割り当てます。これは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_arraynewで割り当てられていないため、deleteを割り当てないでください。配列が(クラスによって個別にヒープ割り当てされて所有されるのではなく)ここにあるようにクラスの一部である場合、デフォルトでクラスの他の部分と一緒に破棄されます。 deleteを呼び出すことは不要であるだけでなく、ほぼ確実にクラッシュを引き起こします。

10
je4d

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];
    }
};
2
Robᵩ

次のコードは似たようなことをしますが、コンストラクターを使用しません。

#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
alarouche

実行時にアレイを作成する必要があります。

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にデフォルトのコンストラクター(つまり、引数をとらないコンストラクター)が必要であることに注意してください。

1
kamprath

代わりにstd :: vectorを使用して、自分の生活をシンプルにしてください。 :)

(固定サイズの配列が必要な場合は、std :: arrayが可能かもしれません。そうでない場合は、C++ 11にあると思いますが、ブーストにはおそらく実装があります)。

ただし、ye-olde Cを使用しているかのように、通常の配列構文を使用する場合は、テンプレートパラメータを使用する必要があります。テンプレートクラスには2つの引数があります。1つはすでにある「T」用です。今、そして配列サイズのためのもう一つ。

その配列を自分で管理することで、人生を特に困難にしています。デストラクタを定義する必要があると感じた場合は、コンストラクタに加えてコピーコンストラクタを定義する必要があります。 (私が正しく思い出せば、これはビッグスリーのルールと呼ばれます)代わりに、RAIIに依存し、演算子deleteまたはdelete []を自分で明示的に呼び出す必要はありません。

0
Arafangion