Push _back用于您自己的STL容器c++

Push _back for your own STL container C++

本文关键字:STL 容器 c++ 自己的 back 用于 Push      更新时间:2023-10-16

我想编写一个用于包含元素序列的类模板。我正在研究一种方法,它的行为就像矢量中的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;

但还是一样。我不知道我的代码出了什么问题。如果大家有什么意见,我将不胜感激。

问题在于你使用了sizeof。它不会告诉你有多少元素,而只告诉你使用了多少内存(N * sizeof(T))。为了跟踪所包含的元素,您可以设置一个单独的计数器。

您要求getmember()返回数组的第一个元素,但setmember()从未填充该元素,除非 Tchar, unsigned charbool,并且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);
}

这应该表明问题:

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类型的方法,不需要一个索引传递值,那么你需要改变你的设计,有一个字段来跟踪到目前为止你已经插入到数组中的元素的数量。

另外,我会做一些检查,看看是否有足够的空间来实际把最新的元素放到数组的后面。

您误解了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;
    }