【问题标题】:Problem with clear() in custom vector STL container自定义向量 STL 容器中的 clear() 问题
【发布时间】:2010-08-08 21:55:56
【问题描述】:

按照 Accelerated 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 指针。当它甚至不修改它时,这怎么可能。代码看起来很简单,但我看不到我缺少什么。

谢谢!

【问题讨论】:

  • Err.. limit 指针在您的输出中是相同的。
  • 我知道。所以我计算容量的方式可能是错误的。如何将 data 设置为零(表示空向量)并且仍然具有等于 128 的容量,例如 std::vector does
  • 容量不是向量的大小。容量是在不增长的情况下可以容纳的元素数量。因此当 size == 0 容量不一定是 0
  • @Andrey,我了解大小和容量之间的区别。我想要 size=0 和 capacity=128,就像 std::vector 在这种情况下所做的那样。

标签: c++ stl stdvector


【解决方案1】:

data 设置为 0 会导致丢失(因此泄漏)。当您清除时,您只会带走可用(已分配)的元素,缓冲区 (data) 会保留。

您应该将data = avail = 0; 替换为avail = data;

【讨论】:

  • 感谢您的回答。我按照你和安德烈的建议设置了avail = data。但是,在这种情况下,在v.clear() 之前,大小 = 100,容量 = 128,而在它之后,大小 = 0,容量 = 28。这并不模仿大小 = 0,容量 = 128 的 std::vector 的行为在这种情况下清除后。怎样才能得到类似的行为?
【解决方案2】:

这并不难。 clear() 应该这样做:

  • 将向量返回到初始状态。 (也将limit 设置为NULL 并释放缓冲内存,比较data = avail = limit = 0;data = avail = 0;
  • 使其为空,但不要缩小。 (保持data 不变,但将avail 设置为data (avail = data))

没有实施这些规则。 (您的 first 版本不正确)这就是您获得不正确容量的原因。

【讨论】:

  • 谢谢!我认为你的第二个建议更接近行为 od std::vector。然而,当我做出改变时,我仍然无法获得这种行为(请参阅我的 cmets 到 GMan)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
  • 2012-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多