在类中声明一个数组,并使用构造函数设置其大小

时间:2012-03-05 02:23:44

标签: c++ arrays class constructor constants

我有一段时间没有使用过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 个答案:

答案 0 :(得分:10)

您遇到编译器错误的原因是这一行:

T this_array[start_size];

此行会使您的Tarray实际包含start_size T个实例。它不会保存指向这些实例的指针或引用 - 它们将是包含Tarray其他实例变量的同一块内存的一部分。 这将使类的大小依赖于start_size,并且在编译时不知道start_size。必须在编译时知道任何C ++类的大小,这是不可能的。

有两种方法可以解决这个问题:

  1. 使用array new在堆上分配T个实例的数组。这就是std::vector的作用。编写这样的类并使其在复制/移动/扩展/等时表现正确是困难和乏味的,所以我建议只使用std::vector代替。
  2. 修复T实例的数量,并将其作为模板参数传递
  3. 即:

    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不仅是不必要的,而且几乎肯定会导致崩溃。

答案 1 :(得分:2)

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 :(得分:2)

以下代码执行类似操作但不使用构造函数:

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

答案 3 :(得分:1)

您必须在运行时创建阵列。

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必须有一个默认构造函数(即不带参数的构造函数)。

答案 4 :(得分:0)

改用std :: vector,让自己变得简单。 :)

(如果你想要一个固定大小的数组,那么std :: array可能是有可能的,我认为这是在C ++ 11中,如果不是,那么boost可能有一个实现)。

如果你坚持使用普通的数组语法,就好像你使用了ye-olde C一样,那么你需要使用一个模板参数,这样你的模板类就有两个参数 - 一个用于'T'它现在已经有了,而另一个用于数组大小。

通过自己管理数组,你的生活变得特别困难 - 如果你觉得必须定义析构函数,除了构造函数之外,你还应该定义复制构造函数。 (这被称为三巨头的规则,如果我没记错的话),相反,依赖RAII并避免必须自己明确地调用操作符删除或删除[]。