C++ Vector 实现分配新对象

Posted

技术标签:

【中文标题】C++ Vector 实现分配新对象【英文标题】:C++ Vector implementation allocating new objects 【发布时间】:2016-10-14 17:14:28 【问题描述】:

我几乎完成了 std::vector 类型向量的实现(希望如此),但我在代码中有一个小错误,我似乎找不到在哪里。基本上,当我构建 Vector 并使用 push_back 时,向量会自动为更多元素分配新内存(特别是向量大小的两倍),但是这样做时,“额外空间”被初始化为 0,我不知道为什么。

这是我的代码:

Vector.h

#include <memory>
#include <cstddef>

template <class T>
class Vec
    public:
        typedef T* iterator;
        typedef const T* const_iterator;
        typedef size_t size_type;
        typedef T value_type;

        Vec()create();
        Vec(size_type n, const T& val = T()) create(n, val);

        ~Vec() uncreate();

        //copy constructor
        Vec(const Vec& v) create(v.begin(), v.end());
        //assignment operator
        Vec& operator=(const Vec&);

        size_type size() const return limit - data;

        //index operators
        T& operator[](size_type i) return data[i];
        const T& operator[](size_type i) const return data[i];

        iterator begin() return data;
        const_iterator begin() const return data;

        iterator end() return limit;
        const_iterator end() const return limit;

        void push_back(const T&);


    private:
        iterator data; //1st element
        iterator avail; //one past last constructed element
        iterator limit; //one past last available element

        //Memory management
        std::allocator<T> alloc;

        void create();
        void create(size_type, const T&);
        void create(const_iterator, const_iterator);

        void uncreate();

        void grow();
        void unchecked_append(const T&);

;

template <class T>
void Vec<T>::push_back(const T& val)
    if(avail == limit)
        grow();
    unchecked_append(val);


template <class T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
    //self-assign
    if(&rhs != this)
        uncreate;
        create(rhs.begin(), rhs.end());
    
    return *this;


// Empty Vector, pointers to 0
template <class T> void Vec<T>::create()
    data = avail = limit = 0;


// Allocate memory for (size)
template <class T> void Vec<T>::create(size_type n, const T& val)
    data = alloc.allocate(n); // returns pointer to first element
    limit = avail = data +n;
    std::uninitialized_fill(data, limit, val);


template <class T> void Vec<T>::create(const_iterator i, const_iterator j)
    data = alloc.allocate(j-i);
    limit = avail =std::uninitialized_copy(i, j, data);


template <class T> void Vec<T>::uncreate()
    if(data)
        iterator it = avail;
        while(it != data)
            alloc.destroy(--it);

        // Free space
        alloc.deallocate(data, limit - data);
    
    // Empty Vector
    data = limit = avail = 0;


template <class T> void Vec<T>::grow()
    // Allocate twice the space we had
    size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1));

    // Allocate new space and copy to new space
    iterator new_data = alloc.allocate(new_size);
    iterator new_avail = std::uninitialized_copy(data, avail, new_data);

    // Return old space used
    uncreate();

    // Reset pointers to point to new space
    data = new_data;
    avail = new_avail;
    limit = data + new_size;


template <class T> void Vec<T>::unchecked_append(const T& val)
    alloc.construct(avail++, val);

这就是我创建矢量的方式

ma​​in.cpp

#include "vector.h"
#incude <iostream>

using namespace std;

int main()
    Vec<int> v1;
    v1.push_back(12);
    v1.push_back(9);
    v1.push_back(74);
    v1.push_back(22);
    Vec<int> v2 = v1;  
    v2.push_back(70); //After doing this the vector is (12, 9, 74, 22, 70, 0, 0, 0)
    for(auto e: v2) cout << e << " ";
    cout << endl;

感谢您的帮助以及对实际代码的任何反馈。 :)

【问题讨论】:

也许你的std::allocator 总是这样,你检查过吗?也许它在调试版本中做到了,是这个吗?您是否尝试过单步执行您的 grow 方法,查看每一步的新数据是什么样的? 我不明白你的意见,v2 怎么能有多个元素呢?你只加了70?还是 70 最终出现在 v1 中? 有错别字,已编辑。我从 v1 开始初始化它。 @Useless 实际上不确定。我只检查 std::vector 没有这样做,所以我的代码中可能有一个错误或者我错过了一些东西/做了一些额外的事情。 我刚刚给了你一个要检查的清单,所以检查一下!您已经在本地安装了分配器的代码,因此请阅读它。您知道(或应该能够找到)您的构建设置和编译器文档。你大概有一个调试器,所以使用它。 【参考方案1】:

问题是(不知道是不是真的问题)

template <class T> void Vec<T>::grow()
    // Allocate twice the space we had
    size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1));
....
....

无需进行任何矢量复制即可重现您的问题。

在插入第 5 个元素后,即使在第一个向量中也可以看到问题

    v1.push_back(12);
    v1.push_back(9);
    v1.push_back(74);
    v1.push_back(22);
    v1.push_back(22);  //5th elemnt.

现在打印尺寸;

cout<<v1.size()<<endl; - it says 8.

即使是标准向量,在 resize() 之后,为空元素打印零也是正常行为。

看这个例子: http://en.cppreference.com/w/cpp/container/vector/resize

如果你不想要额外的零,你必须调整你的 ":new_size" 计算。

【讨论】:

是的。我的意思是做那个 new_size 计算。我的错误只是从类中传递了错误的变量。我正在通过“限制”而不是“可用”。限制是整个数组(包括分配的内存)的末尾。 Avail 是最后一个初始化值的末尾。 就是这样。很好。

以上是关于C++ Vector 实现分配新对象的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中 vector 如何实现内存分配

C++简单实现vector

vector 如何在特定位置调用复制构造函数?

C++ 中vector的重要特点——对象动态增长

如何在 C++ 中向向量中添加新对象

C++ 为啥在向量段错误中放置对象?