我有一段时间没有使用过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.
当我尝试调整代码时,错误消息一直在变化,但这些是来自此特定构建的错误。
感谢您的帮助
答案 0 :(得分:10)
您遇到编译器错误的原因是这一行:
T this_array[start_size];
此行会使您的Tarray
实际包含start_size
T
个实例。它不会保存指向这些实例的指针或引用 - 它们将是包含Tarray其他实例变量的同一块内存的一部分。
这将使类的大小依赖于start_size,并且在编译时不知道start_size。必须在编译时知道任何C ++类的大小,这是不可能的。
有两种方法可以解决这个问题:
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
不仅是不必要的,而且几乎肯定会导致崩溃。
答案 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并避免必须自己明确地调用操作符删除或删除[]。