在没有默认构造函数的情况下减小std :: vector的大小

时间:2013-06-12 00:16:16

标签: c++ stl

我有一个模板化的类使用它的std::vector模板参数。参数可能不是默认的可构造的。我想减少向量的大小(将其剪切为给定的大小)。显然

vec.resize( reduced_size );

...因为需要默认构造函数而无法正常工作。

我当然可以:

  1. 为任何使用过的类型创建默认构造函数(这需要我在可能不是一个好的设计选择时添加它)
  2. 将默认值传递给函数(界面的无用杂乱)
  3. 将构造方法传递给模板(也是无用的混乱)
  4. 在撰写问题时,我注意到我可以erase从向量到结尾的元素:

    vec.erase ( vec.begin() + position, vec.end() );
    

    ...但是,我不确定这是否与resize一样有效。

    在没有默认构造函数的情况下,是否有一种有效的方法来减小向量的大小?

    C ++ 11解决方案是可以接受的。


    编辑:似乎MSVC和GCC都实现了缩小调整大小作为擦除调用,因此这回答了我的性能问题。

3 个答案:

答案 0 :(得分:2)

在我的实现中,它看起来像(有一些简化):

void std::vector<T,A>::resize(size_type __new_size)
{
    if (__new_size > size())
        _M_default_append(__new_size - size());
    else if (__new_size < size())
        _M_erase_at_end(begin() + __new_size);
}

auto std::vector<T,A>::erase(iterator __first, iterator __last) -> iterator
{
    if (__first != __last)
    {
        if (__last != end())
            _GLIBCXX_MOVE3(__last, end(), __first);
        _M_erase_at_end(__first + (end() - __last));
    }
    return __first;
}

其中_M_...是私有成员函数。你真的想要_M_erase_at_end的效果。我猜想编译器很难或不可能优化来自_M_default_append的{​​{1}}调用,但在v.resize(sz) v.erase(iter, v.end())中相对容易注意并优化掉__last == end()_GLIBCXX_MOVE3。因此,+ (end() - __last)可能比erase()更有效率。

我希望大多数实现都是类似的故事:一些简单的resize()测试,然后调用一些相同的方法来调用元素的析构函数。

答案 1 :(得分:1)

当然 - 当你拨打resize时,你可以提供第二个参数,传递一个正确类型的值,如果你使用resize来理论上用它来填补空白点增加矢量的大小。在C ++ 03中,该参数的默认值为T(),这是默认ctor进入的地方(在C ++ 11中,它们使用重载,所以你可以调用resize()来毫不费力地减小尺寸。)

通过传递您自己的值,您可以避免使用默认的ctor。如上所述,在C ++ 11中,即使您没有传递第二个参数,也不需要/使用默认的ctor。

我怀疑与使用erase相比,这会带来任何真正的改善。特别是,标准中的规范是(§23.3.6.3/ 9):

  

如果sz <= size(),相当于erase(begin() + sz, end());

因此,在这种情况下,resizeerase之间似乎没有任何真正的原因。

答案 2 :(得分:1)

您使用erase的想法是正确的选择。为了减少混淆,我会写一个基于容器的算法:

template<typename Container>
Container&& reduce_size( Container&& c, std::size_t amount ) {
  using std::begin; using std::end; // enable ADL
  amount = std::min( amount, std::size_t(end(c)-begin(c)) ); // paranoid!
  c.erase( end(c)-amount, end(c) );
  return std::forward<Container>(c); // I like my container-algorithms to pass through
}

这将与您的erase实施一样快(嗯,还有一个分支和检查)。

使用:

std::vector< Foo > blah;
blah.emplace_back( 7 );
reduce_size( blah, 10 );