关于std :: vector的两个简短问题

时间:2010-07-17 16:14:46

标签: c++ stl vector

  1. 创建向量时,它具有默认的分配大小(可能这不是正确的术语,可能是步长?)。当元素数量达到此大小时,将调整向量的大小。这个尺寸编译器是否具体?我可以控制它吗?这是个好主意吗?
  2. 重复调用vector::size()会重新计算元素数量(O(n)计算),还是将此值存储在某处(O(1)查找)。例如,在下面的代码中

    // Split given string on whitespace
    vector<string> split( const string& s )
    {
        vector<string> tokens;
        string::size_type i, j;
        i = 0;
        while ( i != s.size() ) {
            // ignore leading blanks
            while ( isspace(s[i]) && i != s.size() ) {
                i++;
            }
            // found a word, now find its end
            j = i;
            while ( !isspace(s[j]) && j != s.size() ) {
                j++;
            }
            // if we found a word, add it to the vector
            if ( i != j ) { 
                tokens.push_back( s.substr(i, j-i) );
                i = j;
            }
        }
        return tokens;
    }
    
  3. 假设s可能非常大,我应该只调用s.size()一次并存储结果吗?

    谢谢!

6 个答案:

答案 0 :(得分:5)

在大多数情况下,您应该单独保留分配,除非您提前知道项目数,因此您可以保留正确的空间量。

至少在我知道的每种情况下,std::vector::size()只返回一个存储值,因此它具有恒定的复杂性。从理论上讲,C ++标准允许它做其他事情。有理由允许其他容器,主要是std::list,而不是为那些容器做特殊情况,他们只是建议所有容器的恒定时间,而不是任何容器。我无法想象一个vector::size计算了元素 - 我真的没有这样的事情存在过。

P.S。,更简单的方法来执行上面的代码所做的事情,就像这样:

std::vector<string> split(std::string const &input) {
    vector<string> ret;
    istringstream buffer(input);

    copy(istream_iterator<string>(input),
         istream_iterator<string>(),
         back_inserter(ret));

    return ret;
}

编辑:IMO, C ++标准库,由Nicolai Josuttis撰写,是关于此类事情的绝佳参考。

答案 1 :(得分:4)

容量增量的实际大小取决于实现,但必须(大致)指数以支持容器的复杂性要求。例如,Visual C ++标准库将精确分配前几个元素所需的空间(五个,如果我没记错的话),然后在那之后以指数方式增加大小。

大小必须以某种方式存储在向量中,否则它不知道序列的结尾在哪里!但是,它可能不一定存储为整数。 Visual C ++实现(再次作为示例)存储三个指针:

  1. 指向底层数组开头的指针
  2. 指向序列当前结束的指针,
  3. 指向底层数组末尾的指针。
  4. 大小可以从(1)和(2)计算出来;容量可以从(1)和(3)计算出来。

    其他实现可能会以不同方式存储信息。

答案 2 :(得分:1)

  1. 这是特定于图书馆的。您可以控制增量分配,但可能不会。

  2. 存储大小,因此检索速度非常快(恒定时间)。它还有什么用呢? C无法一般地知道内存位置是否是“真实数据”。

答案 3 :(得分:1)

  1. 调整大小机制通常是固定的。 (大多数编译器在达到限制时将向量的大小加倍。)C ++标准指定无法控制此行为。

  2. 每当您插入/删除元素时,内部都会更新大小,当您调用size()时,会立即返回。所以,是的,它是 O(1)

答案 4 :(得分:1)

  

当元素数量达到此大小时,将调整矢量大小。这个尺寸编译器是否具体?我可以控制它吗?这是个好主意吗?

通常,这是特定于库的行为,但是可能可以通过指定自定义分配器来影响此行为,这是非常重要的工作。

  

重复调用vector :: size()会重新计算元素数量(O(n)计算),或者将此值存储在某处(O(1)lookup)。

大多数实现将大小存储为成员。这是一个单一的内存读取。

答案 5 :(得分:1)

与您的实际问题无关,但这是一种更“STL”的方式来做您正在做的事情:

vector<string> split(const string& s)
{
    istringstream stream(s);
    istream_iterator<string> iter(stream), eos;
    vector<string> tokens;
    copy(iter, eos, back_inserter(tokens));
    return tokens;
}
相关问题