2013-09-24 73 views
5

卡在11練習11-6的擦除功能。我已經銷燬了這些對象,但我不知道如何使用allocator庫中的釋放來返回空間。加速C++練習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 ; 

} 
+0

什麼是你真正想幹什麼? – thecoshman

回答

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

更好的選擇是這種標準方式。添加額外的構造函數, 交換和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(); 
2

我想,那解決方案之一是創建具有以下大小的新載體:

new_size = old_size - number_of_elements_to_delete 

然後你從開始複製對象到第一個刪除對象,從最後一個刪除對象到結束,然後釋放舊的向量。

這不是最好的解決方案,但我認爲最簡單。

+0

謝謝你的回覆,我想我在做什麼也沒壞,我只是不knwo如何使用成員函數解除分配分配。所以我主要需要幫助。謝謝 – samprat

2

這裏有一個reference page for std::allocator::deallocate得到了什麼,說:

void deallocate(pointer p, size_type n);

解除分配由指針p,它必須是由較早的調用allocate()獲得一個指針引用的存儲。參數n必須等於allocate()最初產生的p的第二個參數。

也就是說,您無法取消分配您分配的部分存儲空間,而只能釋放整個塊。

的解決方案是不返回由自由通過調用erase存儲。只需相應地更新您的成員迭代器,以便隨後調用create以保持此存儲空間的可用性。這也是標準容器vector所做的。

如果你真的想返回多餘的存儲,分配一個較小的臨時塊,複製停留在容器中存在的元素,釋放舊的存儲和更新迭代器。

事情要記住這裏是異常安全。一旦分配了臨時緩衝區,在複製元素期間發生異常時,您需要確保不會泄漏它。

2

由於羅和其他人所說的,你不能解除分配內存的一部分 - 你需要解除分配entire referenced storage

還有一個更重要的事情 - 如果你通過第11章(具體而言,11.4下,動態血管內皮細胞),你會注意到,push_back()實施加倍底層數組的大小一旦達到當前最大尺寸。

類似的路線,你會想減半底層數組的大小時,你的矢量的大小成爲當前最大尺寸的四分之一。這是當你需要重新分配內存並呼籲std::allocator::deallocate釋放多餘的存儲。