我有一个模板化的类使用它的std::vector
模板参数。参数可能不是默认的可构造的。我想减少向量的大小(将其剪切为给定的大小)。显然
vec.resize( reduced_size );
...因为需要默认构造函数而无法正常工作。
我当然可以:
在撰写问题时,我注意到我可以erase
从向量到结尾的元素:
vec.erase ( vec.begin() + position, vec.end() );
...但是,我不确定这是否与resize
一样有效。
在没有默认构造函数的情况下,是否有一种有效的方法来减小向量的大小?
C ++ 11解决方案是可以接受的。
编辑:似乎MSVC和GCC都实现了缩小调整大小作为擦除调用,因此这回答了我的性能问题。
答案 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());
。
因此,在这种情况下,resize
和erase
之间似乎没有任何真正的原因。
答案 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 );