我的载体有时起作用,有时却不起作用

时间:2018-12-20 20:11:41

标签: c++

我正在尝试制作自己的向量,但遇到以下问题:当我push_back 100次时,没有问题。当我push_back 1000时,程序无法运行

#include <iostream>
#include <stdlib.h>
#include <conio.h>

struct Exception {
    static const char* out_of_range;
};

const char* Exception::out_of_range = "[Error]: Out of range";

template < typename T >
struct vector {
    typedef T myType;
public:
    vector() { 
        m_vector = (myType*) malloc ( sizeof( myType ) );
        m_position = 0; 
    }
    template < typename ... Ts >
    vector(myType head, Ts ... tail) {
        m_position = 0;
        m_vector = (myType*) malloc( (sizeof ...( tail ) + 1) * sizeof( myType ) );
        this->push_back(head);
        (this->push_back(tail),...);
    }
    ~vector() { 
        free(m_vector); 
        m_vector = NULL;
    }
    void push_back( myType value ) {
        m_vector[ m_position ] = value;
        ++m_position;
        m_vector = (myType*) realloc(m_vector, m_position * sizeof(myType));
    }
    void pop_back() {
        --m_position;
        m_vector = (myType*)realloc( m_vector, m_position * sizeof (myType) );
    }

    myType at( size_t pos ) {
        try {
            if (pos < m_position) 
                return m_vector[ pos ];
            else throw Exception::out_of_range;
        } catch (const char* e) {
            printf("%s", e);
            return (myType){};
        }
    }

    inline myType& front() { return *m_vector; }
    inline myType& back() { return *(m_vector + size() -1); }
    inline myType* data() { return m_vector; }

    inline myType* begin() { return m_vector; }
    inline myType* end() { return (m_vector + size()); }

    inline myType operator[](size_t pos) { return m_vector[ pos ]; }
    inline size_t size() { return m_position; }
    inline bool empty () { return (begin() == end()? true:false); }

private:
    myType* m_vector;
    size_t m_position;
};

这是我主要使用push_back的100次:

int main() {
    vector<int> v;
    for(int i = 0; i < 100; ++i) v.push_back(i);
    for(int i = 0; i < 100; ++i) std::cout << v[i];
}

下面是被搜寻的代码:

int main() {
    vector<int> v;
    for(int i = 0; i < 1000; ++i) v.push_back(i);
    for(int i = 0; i < 1000; ++i) std::cout << v[i];
}

对于“不起作用”,我想说的是,当我通过push_back插入100个值时,程序会向我显示0到99之间的所有值...但是当我有1000个值时(我不会(不知道为什么),该程序仅显示黑屏,仅此而已

2 个答案:

答案 0 :(得分:4)

考虑

的首次通话
void push_back(myType value) {
    m_vector[m_position] = value; // Store into 0
    ++m_position; // set `m_position` to 1
    m_vector = (myType*)realloc(m_vector, m_position * sizeof(myType)); // Allocate more space.
}

最后一行分配了多少空间? m_position * sizeof(myType)。解析为1 * sizeof(myType)。 1 myType的空间足够。换句话说,程序已经具有相同的空间量。这没有用。

让我们看看下一个push_back

void push_back(myType value) {
    m_vector[m_position] = value; // Store into 1. There is no 1. Program now broken
    ++m_position; // set `m_position` to 2
    m_vector = (myType*)realloc(m_vector, m_position * sizeof(myType)); // Allocate more space.
}

下一个push_back写入无效的存储。程序现已正式破坏,无需进一步调试。

我们如何解决这个问题?

让我们忽略一个事实,即malloc以及家庭don't handle complex data structuresvector没有遵守the Rules of Three and Five。最好在其他问题中解决这些问题。我们如何用realloc来解决这个问题?

m_vector = (myType*) realloc(m_vector, (m_position +1) * sizeof(myType));

使当前的粗糙区域变得平滑。但这效率低下。每次添加都会触发重新分配。这确实确实损害了性能。聚合O(1)随即被O(n)所取代,每次复制,再加上可能非常昂贵的内存分配。 1

更糟糕的是,删除项目时会发生什么?您无法掌握向量中的多少,并且可能会发现自己realloc正在使用较小的缓冲区。好吧。

要正确执行此操作,首先添加一个m_capacity成员以跟踪可以存储多少数据,这样,如果所需数量少于所需数量,我们就不必重新分配。

然后我们测试空间量,并可能在尝试存储之前重新分配。

void push_back( myType value ) {
    if (m_position >= m_capacity)
    { // need to reallocate
        m_capacity *= 2;
        myType * temp = (myType*) realloc(m_vector, m_capacity *sizeof(myType));
        // ask for more than is needed. Reduce number of reallocations needed
        // do not overwrite m_vector. realloc can fail to allocate and then where are you?
        if (temp != NULL) 
        { 
            m_vector = temp;
        }
        else
        {
             // handle error. Probably throw exception. Definitely exit function 
             // before trying to add new element
        }
    }
    m_vector[ m_position ] = value; // now guarantied to have space.
    ++m_position;
}

1 严格来说,这不是真的。您会发现的一件事是,所提供的内存通常不如您所要求的那样精细。当程序要求X字节时,它可能会获得一个方便的空闲内存块,该块大于X字节。您曾经注意到,有时您可以在缓冲区末尾运行,而程序没有注意到并立即崩溃?多余的空间是原因之一。 realloc经常可以利用这一优势,并一遍又一遍地使用相同的分配,从而使程序可以合法地查看更多信息。但是,您不能指望这一点。

答案 1 :(得分:2)

我假设您的代码背后的想法是m_vector应该总是比现在拥有更多的值。那么您的push_back函数是错误的,应该为m_position + 1重新分配。