我想编写一个用于包含元素序列的类模板。我正在研究一种方法,其行为类似于向量中的push_back()。这就是我到目前为止所做的:
template <class T, int N>
class mysequence{
T memblock[N];
public:
void setmember(T value);
T getmember(int x);
};
template <class T, int N>
void mysequence<T, N>::setmember(T value) {
if (sizeof(memblock) == 1) memblock[0] = value;
else {
int y = sizeof(memblock) / sizeof(memblock[0]);
memblock[y] = value;
}
}
template <class T, int N>
T mysequence<T, N>::getmember(int x) {
return memblock[x];
}
int main()
{
mysequence < int, 14 > myints;
myints.setmember(9);
cout << myints.getmember(0);
}
它返回:
-858993460
带有错误消息。据我所知,空类或结构的大小为1.但我也尝试过:
if (sizeof(memblock) == NULL) memblock[0] = value;
但都一样。我无法弄清楚我的代码有什么问题。如果有人有任何想法,我会压制它。
答案 0 :(得分:1)
你使用sizeof有什么问题。它不会告诉您有多少元素,而只是使用的内存(N * sizeof(T))。为了跟踪所包含的元素,你可以选择一个单独的计数器。
答案 1 :(得分:0)
您要求getmember()
返回数组的第一个元素,但setmember()
永远不会填充该元素,除非 T
为char
,unsigned char
或bool
,N
为1.在任何其他组合中,setmember()
将值存储在数组末尾 。如果您想在最后一个元素中存储值,请改用N-1(无需计算y
,因为它将匹配N
):
template <class T, int N>
void mysequence<T, N>::setmember(T value) {
memblock[N-1] = value;
}
但是,这在多元素数组中没用。由于您要模仿push_back()
,因此您需要setmember()
将值存储在最后一个可用元素中:
template <class T, int N>
class mysequence{
T memblock[N];
int count;
public:
mysequence() : count(0) {}
void setmember(T value);
T getmember(int x);
};
template <class T, int N>
void mysequence<T, N>::setmember(T value) {
if (count < N) {
memblock[count-1] = value;
++count;
}
else
throw length_error("sequence is full");
}
template <class T, int N>
T mysequence<T, N>::getmember(int x) {
if ((x < 0) || (x >= count))
throw out_of_range("x is out of range");
return memblock[x];
}
int main()
{
mysequence < int, 14 > myints;
myints.setmember(9);
cout << myints.getmember(0);
}
或者,你可以简单地摆脱你的数组并使用真正的向量:
template <class T>
class mysequence{
vector<T> memblock;
public:
void setmember(T value);
T getmember(int x);
};
template <class T>
void mysequence<T>::setmember(T value) {
memblock.push_back(value);
}
template <class T>
T mysequence<T>::getmember(int x) {
return memblock[x];
}
int main()
{
mysequence < int > myints;
myints.setmember(9);
cout << myints.getmember(0);
}
答案 2 :(得分:0)
这应该表明问题:
template <class T, int N>
void mysequence<T, N>::setmember(T value) {
if (sizeof(memblock) == 1) memblock[0] = value;
else {
int y = sizeof(memblock) / sizeof(memblock[0]);
cout << "y: " << y << endl;
memblock[y] = value;
}
}
使用时调用:
myints.setmember(1);
myints.setmember(5);
myints.setmember(8);
我得到了输出:
y: 14
y: 14
y: 14
y
总是相同的,因为它是通过查找底层存储阵列的长度来计算的,而不是实际存储在该数组中的元素数。
鉴于我们没有正确填充数组的元素,我们调用getmember
时得到的值将拉出数组的未初始化元素。这是从-858993460
获取垃圾值的地方(请注意,在我的机器上,我在这里得到的值与我们在这里的UB一致)。
如果您想支持push_back
类型的方法,该方法不需要使用值传入索引,那么您需要将设计更改为具有跟踪您有多少元素的字段到目前为止已插入数组。
另外,我会做一些检查,看看是否有足够的空间在进行之前将最新的元素放入数组的后面。
答案 3 :(得分:0)
您误解了push_back的功能。 push_back的作用是它将元素添加到数组的末尾,甚至是空数组。所以我修改了你的函数的一些功能,并在评论中指出了它们。
#include <iostream>
#include <algorithm>
using namespace std;
template <class T, int N>
class mysequence{
T *memblock;//You will need a pointer for enabling the resizing of the array
int size;//This is used to keep track of the size of the array
public:
mysequence();
mysequence(const mysequence &src);
~mysequence();
void setmember(T value);
T getmember(int x);
void push_back(T value);
mysequence& operator=(const mysequence &src);
};
template <class T, int N>
void mysequence<T, N>::mysequence(){
size = N;
memblock = new T[N];
}
template <class T, int N>
void mysequence<T, N>::mysequence(const mysequence<T,N> &src){
size = src.size
memblock = new T[size];
copy(src.memblock, src.memblock+size, memblock);
}
template <class T, int N>
void mysequence<T, N>::~mysequence(){
delete[] memblock;
}
template <class T, int N>
void mysequence<T, N>::setmember(T value) {//this setmember function just sets the last element of the array to the value specified
if( size > 0 ){
memblock[size-1] = value;
}
}
template<class T, int N>
void mysequence<T,N>::push_back(T value){
T *pointer = new T[size+1];
copy(memblock, memblock+size, pointer);
pointer[size] = value;
delete[] arr;
arr = pointer;
size++;
}
template <class T, int N>
T mysequence<T, N>::getmember(int x) {
return memblock[x];
}
template<class T, int N>
mysequence<T,N>& mysequence<T,N>::operator=(const mysequence<T,N> &src){
T *pointer = new T[src.size];
copy(src.memblock, src.memblock+src.size, pointer);
delete[] arr;
arr = pointer;
size = src.size;
}
int main()
{
mysequence < int, 14 > myints;
myints.setmember(9);
cout << myints.getmember(13)<<endl;//the indexing is one less. so to access the last element, you need to specify 13. As other values are not initialized, they will have garbage value in them
myints.push_back(1);
cout<<myints.getmember(14)<<endl;
return 0;
}