为您自己的 STL 容器 C++ 推送 _back

Push _back for your own STL container C++

我想编写一个 class 模板,用于包含元素序列。我正在研究一种在向量中表现得像 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);

    }

它 returns:

-858993460

有错误信息。据我所知,空 class 或结构的大小为 1。但我也尝试过:

if (sizeof(memblock) == NULL) memblock[0] = value;

但都一样。我不知道我的代码有什么问题。如果有人有什么想法,我会提出来的。

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

您要求 getmember() 到 return 数组的第一个元素,但是 setmember() 永远不会填充该元素 除非 Tcharunsigned 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 类型的方法,不需要将索引与值一起传递,那么您需要更改您的设计以拥有一个字段来跟踪有多少到目前为止您已插入数组的元素。

此外,我会做一些检查,看看是否有足够的 space 在执行之前将最新的元素实际放入数组的后面。

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