Проблема с clear () в пользовательском векторном контейнере STL - PullRequest
2 голосов
/ 09 августа 2010

Следуя примеру в Ускоренное C ++ , я создал собственный контейнер STL, который является упрощенной версией std::vector, которая называется Vec. Все работало нормально, пока, воодушевленный успехом, я не попытался добавить Vec::clear(), который очистит вектор.

Вот последнее определение класса (только соответствующие части этого вопроса):

template <class T>
class Vec {
public:
    Vec() { create(); }

    size_type size() const { return avail - data; }
    size_type capacity() const { return limit - data; }
    void clear();

    // operators that return iterators
    iterator begin() { return data; }
    const_iterator begin() const { return data; }
    iterator end() { return avail; }
    const_iterator end() const { return avail; }

    void push_back( const T& val ) {
        if ( avail == limit ) grow();
        unchecked_append( val );
    }       
private:
    iterator data;  // points to beginning of data 
    iterator avail; // points to end of initialized data
    iterator limit; // points to end of data

    std::allocator<T> alloc;    // object to handle data allocation

    void create();
    // functions to support push_back()
    void grow();
    void unchecked_append( const T& );
};

// Creates an empty vector.
template <class T> 
void Vec<T>::create() { data = avail = limit = 0; }

// All the elements of the vector are dropped: their destructors are called, 
// and then they are removed from the vector container, 
// leaving the container with a size  of 0. 
// The capacity remains the same, however.
template <class T>
void Vec<T>::clear()
{
    std::cout << "capacity before clear: " << capacity() << std::endl;
    std::cout << "data = " << data << " limit = " << limit << std::endl;
    if (data) {
        iterator it = avail;
        // destroy objects in reverse order
        while ( it != data ) {
            alloc.destroy(--it);
        }
    }
    data = avail = 0;
    std::cout << "capacity after clear: " << capacity() << std::endl;
    std::cout << "data = " << data << " limit = " << limit << std::endl;
}

// Controls how the vector should grow if it needs more space.
template <class T>
void Vec<T>::grow()
{
    // Allocate twice as much storage as is currently used.
    // If matrix is empty, allocate one element.
    size_type new_size = std::max( 2*(limit-data), ptrdiff_t(1) );

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

    // Deallocate old space
    uncreate();

    // Reset pointers to new values
    data = new_data;
    avail = new_avail;
    limit = data + new_size;
}

// Create space for one element at the end and put given value there.
template <class T>
void Vec<T>::unchecked_append( const T& val )
{
    alloc.construct( avail, val );
    avail++;
}

Я проверяю это, используя

Vec<int> v;

for ( int i = 0; i < 100; i++ ) {
    v.push_back(i);
}
std::cout << "size=" << v.size() << " capacity=" << v.capacity() << std::endl;
v.clear();
std::cout << "size=" << v.size() << " capacity=" << v.capacity() << std::endl;

Я получаю следующий вывод:

size=100 capacity=128
capacity before clear: 128
data = 0x100100280 limit = 0x100100480
capacity after clear: 1074004256
data = 0 limit = 0x100100480
size=0 capacity=1074004256

По какой-то причине clear() перекрывает указатель limit. Как это может быть, когда это даже не изменяет это. Код выглядит так просто, но я не вижу, что мне не хватает.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 09 августа 2010

Вы теряете (и, следовательно, теряете) data, устанавливая его в 0. Когда вы очищаете, вы только удаляете доступные (выделенные) элементы, буфер (data) остается.

Вы должны заменить data = avail = 0; на avail = data;.

1 голос
/ 09 августа 2010

Это не сложно.clear() должен сделать либо:

  • вернуть ваш вектор в исходное состояние.(установите limit на NULL также и освободите буферную память, сравните data = avail = limit = 0; с data = avail = 0;)
  • сделайте его пустым, но не уменьшайте(оставьте data как есть, но установите avail в data (avail = data))

, но не эти правила реализованы.(у вас плохая версия первой), поэтому вы получаете неправильную емкость.

...