【问题标题】:std::allocator not preserving old allocated items after reallocationstd::allocator 在重新分配后不保留旧分配的项目
【发布时间】:2012-06-18 23:53:04
【问题描述】:

我正在尝试实现一个分配内存块的 Vector 类,如果它需要包含更多项目,最终会重新分配它。
我正在使用 std::allocator 来执行此操作:

#include <iostream>
#include <stdexcept>

using namespace std;

template <class T>
class Vector
{
private:
    T* data;
    allocator<T> data_all;
    int length;
    int _size;
    static const int block_size=10;
    void init()
    {
        length=0;
        _size=block_size;
        data=data_all.allocate(block_size,NULL);
    }
public:
    Vector()
    {
        init();
    }
    int size() const
    {
        return length;
    }
    void push_back(T item)
    {
        length++;
        if(length > _size)
        {
            _size+=block_size;
            data=data_all.allocate(_size,data);
        }
        data_all.construct(&data[length-1],item);
    }
    T& operator[] (int i)
    {
        if(i<0 || i>= length)
            throw out_of_range("The index is out of vector range");
        return data[i];
    }
};

int main(int argc, char** argv)
{
    Vector<int> v;
    for(int i=0; i<20; i++)
        v.push_back(i);
    for(int i=0; i<v.size(); i++)
        cout << v[i] << "\t";
    return 0;
}

问题是先前分配的项目没有保留,它打印:

0   0   0   0   0   0   0   0   0   0   10  11  12  13  14  15  16  17  18  19  

代替:

0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19  

为什么会有这种行为?在 C++ 中没有办法像在 C 中使用 realloc 重新分配连续项目吗?

【问题讨论】:

    标签: c++ allocator


    【解决方案1】:

    allocate 的第二个参数只是一个提示,分配器 可以 用来尝试返回靠近旧内存的新内存,但被 std::allocator 忽略,并且对向量毫无用处- 类似容器,因为无论如何所有元素都彼此靠近,因为它们位于一个连续的块中。

    您似乎希望它复制现有数据。它不会。你必须这样做,从旧内存块复制到新内存块。

    您还泄漏了旧内存。你需要释放它。

    你想要这样的东西:

    void push_back(const T& item)
    {
        if (length == _size)
        {
            T* new_data = data_all.allocate(_size+block_size);
            // N.B. if any of the following copies throws new_data will be leaked
            std::uninitialized_copy(data, data+length, new_data);
            std::destroy(data, data+length);
            data_all.deallocate(data, _size);
            data = new_data;
            _size+=block_size;
        }
        data_all.construct(&data[length++],item);
    }
    

    【讨论】:

    • 难道没有另一种方法,至少尝试将新块分配到一个连续的位置(如 C 中的 realloc)?
    • 简答:否。长回答:realloc 只需要处理原始的、未初始化的内存,C++ 向量中的一块内存将包含需要通过运行析构函数来销毁的初始化对象,这要复杂得多,尤其是在您需要确保异常安全的情况下。
    • 由于std::allocator::allocate 返回未初始化的内存,我认为您想在push_back 示例中使用std::uninitialized_copy 而不是std::copy
    • 为了提高性能,我想我会使用 malloc 和 realloc 来分配指针,每个指针都会用 new 初始化。
    猜你喜欢
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    • 2013-04-03
    相关资源
    最近更新 更多