5

卡在第 11 章练习 11-6 的擦除功能中。我已经销毁了这些对象,但我不知道如何使用分配器库中的释放来返回空间。

请保释我。PS:这不是作业,但我正在家里练习

下面是来自 Accelerated C++ 的代码,然后是我修改后的擦除函数。谢谢`

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

    Vec() { create(); }
    explicit Vec(size_type n, const T& t = T()) { create(n, t); }
    Vec(const Vec& v) { create(v.begin(), v.end()); }
    Vec& operator=(const Vec&);
    ~Vec() { uncreate(); }

    T& operator[](size_type i) { return data[i]; }
    const T& operator[](size_type i ) const { return data[i]; }

    void push_back(const T& t)
    {
        if (avail == limit)
        {
            grow();
        }

        unchecked_append(t);
    }

    iterator erase(iterator);
    iterator erase( iterator, iterator );
    void clear();

    size_type size() const { return avail - data; }

    iterator begin() { return data; }
    const iterator begin() const { return data; }

    iterator end() { return avail; }
    const iterator end() const { return avail; }

private:
    iterator data;
    iterator avail;
    iterator limit;

    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> typename Vec<T>::iterator Vec<T>::erase(iterator  first, iterator second )
{
    if( second < first )
    {
        throw std::out_of_range("Iterator out of bounds.");
    }
    if( first < data || second >= avail )
    {
        throw std::out_of_range("Iterator out of bounds.");
    }
    iterator last = avail -1 ;
    iterator i = first ;
    iterator j = second ;  
    while( j <= last )
    {
        *i++ = *j++ ;

    }
    // destroy each initilsed space 
    iterator new_avail =  avail -  first + second ;

    std::cout << " end " << end() << std::endl;

    while( avail != new_avail )
    {
        alloc.destroy(--avail ) ;
    }


    // dellocate  space how to do  that ?
    alloc.deallocate( avail -1,  );  // not sure  what to do  here 
    return first ;

}
4

4 回答 4

4

您不能释放分配的内存的一部分。那

alloc.deallocate(avail -1, );

不好。

编辑

您不应该尝试在擦除中管理分配。您可以选择重新分配它,这将使擦除更加昂贵。第二个功能可以做:

iterator shrink(iterator first, iterator last) {

    size_type capacity = (limit - data) - (last - first);

    iterator new_data = alloc.allocate(capacity);
    iterator new_avail = new_data;
    iterator source = data;
    while(source < first)
        // C++11
        alloc.construct(new_avail++, std::move(*source++));
    source = last;
    iterator result = new_avail;
    while(source < avail)
        // C++11
        alloc.construct(new_avail++, std::move(*source++));
    while(data < avail)
        alloc.destroy(--avail);
    data  = new_data;
    avail = new_avail;
    limit = new_data + capacity;

    return result;
}

更好的选择是这种标准方式。添加一个额外的构造函数,swap 和 shrink_to_fit:

Vec(const_iterator first, const_iterator last) {
    create(first, last);
}

void swap(Vec& other) {
    std::swap(data, other.data);
    ...
}

bool shrink_to_fit() {
    try
    {
        Vec(begin(), end()).swap(*this);
        return true;
    }
    catch(...) {}
    return false;
}

现在您可以对向量应用多个操作并最终减少内存消耗。

 v.erase(a, b);
 v.erase(c, d);
...
v.shrink_to_fit();
于 2013-09-24T15:43:47.940 回答
2

我想,解决方案之一是创建一个具有以下大小的新向量:

new_size = old_size - number_of_elements_to_delete

然后将对象从开始复制到第一个擦除对象,从最后一个擦除对象复制到结束,然后释放旧向量。

这不是最好的解决方案,而是我想的最简单的解决方案。

于 2013-09-24T14:30:06.060 回答
2

这是参考页面std::allocator::deallocate必须说的:

void deallocate( pointer p, size_type n );

释放指针引用的存储空间,该指针p必须是通过先前调用获得的指针allocate()。该参数n必须等于对allocate()最初生成的调用的第二个参数p

也就是说,您不能释放您分配的存储的一部分,只能释放整个块。

解决方案是不返回调用erase. 只需相应地更新您的成员迭代器,以便您保持此存储可用于后续调用create. 这也是标准容器的vector作用。

如果你真的想返回多余的存储,分配一个较小的临时块,复制留在容器中的元素,释放旧存储并更新迭代器。

这里要记住的是异常安全。分配临时缓冲区后,您需要确保不会泄漏它,以防在复制元素期间发生异常。

于 2013-09-30T10:10:57.357 回答
2

正如 jrok 和其他人所提到的,您不能释放部分内存 - 您需要释放整个引用的存储空间

还有一件更重要的事情——如果你仔细阅读第 11 章(特别是在 11.4 节,Dynamic Vecs下),你会注意到push_back()一旦底层数组达到当前最大大小,它的实现就会将其大小加倍。

在类似的行中,当向量的大小变为当前最大大小的四分之一时,您希望将底层数组的大小减半。这是您需要重新分配内存并调用以释放多余存储空间的时候。std::allocator::deallocate

于 2013-09-30T10:42:50.197 回答