8

我有一个使用std::vector模板参数的模板类。该参数可能不是默认可构造的。我想减小向量的大小(将其切成给定的大小)。明显地

vec.resize( reduced_size );

...不起作用,因为它需要默认构造函数。

我当然可以:

  1. 为任何使用的类型创建默认构造函数(当它可能不是一个好的设计选择时需要我添加它)
  2. 将默认值传递给函数(无用的界面混乱)
  3. 将构造方法传递给模板(也是无用的混乱)

在写这个问题时,我注意到我可以erase从向量到最后的元素:

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

...但是,我不确定这是否会像resize.

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

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


编辑:似乎 MSVC 和 GCC 都将缩小大小调整为擦除调用,这样就回答了我的性能问题。

4

3 回答 3

2

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

template<typename Container>
Container&& reduce_size( Container&& c, std::size_t amount ) {
  amount = std::min( amount, c.size() ); // 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 );
于 2013-06-12T00:28:02.013 回答
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调用v.resize(sz),但相对容易注意到v.erase(iter, v.end())__last == end()优化掉_GLIBCXX_MOVE3+ (end() - __last)。所以erase()很可能比resize()这里更有效率。

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

于 2013-06-12T00:43:32.910 回答
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());

resize因此,erase在这种情况下,似乎没有任何区别的真正原因。

于 2013-06-12T00:27:01.217 回答