加速C++练习 11-6

Accelerated C++ exercise 11-6

本文关键字:11-6 练习 C++ 加速      更新时间:2023-10-16
在第

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

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

以下是来自加速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 ;
}

不能解除分配已分配内存的一部分。那

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;
}

更好的选择是这种标准方式。添加一个额外的构造函数, 交换和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();

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

new_size = old_size - number_of_elements_to_delete
然后,

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

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

以下是

std::allocator::deallocate的参考页面必须说的内容:

void deallocate( pointer p, size_type n );

解除分配指针p引用的存储,该存储必须是先前调用allocate()获得的指针。参数n必须等于最初生成p的调用allocate()的第二个参数。

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

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

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

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

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

还有一件更重要的事情 - 如果您浏览第 11 章(特别是 11.4 下的动态 Vecs(,您会注意到 push_back() 的实现一旦达到当前最大大小,底层数组的大小就会加倍。

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