[英]Reducing the size of a std::vector without a default constructor
I have a templated class using a std::vector
of it's template argument.我有一个使用
std::vector
模板参数的模板化类。 The argument may not be default constructible.该参数可能不是默认可构造的。 I want to reduce the size of the vector (cut it to a given size).
我想减小向量的大小(将其切成给定的大小)。 Obviously
明显地
vec.resize( reduced_size );
...doesn't work as it requires a default constructor. ...不起作用,因为它需要默认构造函数。
I could of course:我当然可以:
While writing the question, I noticed that I can erase
the elements from the vector up to the end:在写这个问题时,我注意到我可以从向量中
erase
元素直到最后:
vec.erase ( vec.begin() + position, vec.end() );
... however, I'm not sure if this will be as efficient as resize
. ...但是,我不确定这是否与
resize
一样有效。
Is there an efficient way to reduce a vector's size without a default constructor?有没有一种有效的方法可以在没有默认构造函数的情况下减小向量的大小?
C++11 solutions are acceptable. C++11 解决方案是可以接受的。
EDIT: Seems that both MSVC and GCC implement shrinking resize as a erase call, so that answers my performance question.编辑:似乎 MSVC 和 GCC 都将缩小调整大小作为擦除调用来实现,因此可以回答我的性能问题。
Your idea to use erase
is the right route.您使用
erase
想法是正确的途径。 To reduce the amount of confusion, I would write a container based algorithm:为了减少混淆,我会写一个基于容器的算法:
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
}
which will be as fast as your erase
implementation (well, one more branch and check).这将与您的
erase
实现一样快(好吧,再进行一次分支检查)。
Use:用:
std::vector< Foo > blah;
blah.emplace_back( 7 );
reduce_size( blah, 10 );
In my implementation, it looks like we have (with a few simplifications):在我的实现中,看起来我们有(有一些简化):
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;
}
where _M_...
are private member functions.其中
_M_...
是私有成员函数。 You really want the effects of _M_erase_at_end
.你真的想要
_M_erase_at_end
的效果。 I would guess it would be hard or impossible for a compiler to optimize the _M_default_append
call out of v.resize(sz)
, but relatively easy to notice in v.erase(iter, v.end())
that __last == end()
and optimize away the _GLIBCXX_MOVE3
and the + (end() - __last)
.我猜想编译器很难或不可能从
v.resize(sz)
优化_M_default_append
调用,但在v.erase(iter, v.end())
中相对容易注意到__last == end()
并优化掉_GLIBCXX_MOVE3
和+ (end() - __last)
。 So erase()
could very well be more efficient than resize()
here.所以这里的
erase()
很可能比resize()
更有效。
I would expect most implementations to be a similar story: a few simple if
tests, and then calling some identical method to call destructors for elements at the end.我希望大多数实现都是一个类似的故事:一些简单的
if
测试,然后调用一些相同的方法来调用最后元素的析构函数。
Sure -- when you call resize
, you can supply a second parameter passing a value of the correct type that would (theoretically) be used to fill in the empty spots if you use resize
to increase the size of the vector.当然 - 当您调用
resize
,您可以提供第二个参数传递正确类型的值,如果您使用resize
来增加向量的大小,该值将(理论上)用于填充空位。 In C++03, that argument has a default value of T()
, which is where the default ctor comes into things (in C++11, they use overloading instead, so you can call resize()
to reduce size without any further difficulty).在 C++03 中,该参数的默认值为
T()
,这是默认构造函数出现的地方(在 C++11 中,它们使用重载代替,因此您可以调用resize()
来减小大小而无需任何进一步的困难)。
By passing a value of your own, you avoid the need for the default ctor.通过传递您自己的值,您可以避免使用默认构造函数。 As noted above, in C++11, the default ctor won't be needed/used even if you don't pass the second argument.
如上所述,在 C++11 中,即使您不传递第二个参数,也不需要/使用默认的构造函数。
I doubt this will give any real improvement compared to using erase
though.我怀疑与使用
erase
相比,这会带来任何真正的改进。 In particular, the specification in the standard is (§23.3.6.3/9):特别是,标准中的规范是(§23.3.6.3/9):
If
sz <= size()
, equivalent toerase(begin() + sz, end());
如果
sz <= size()
,相当于erase(begin() + sz, end());
..
As such, there seems to be no real reason for any difference between resize
and erase
in this case.因此,在这种情况下,
resize
和erase
之间似乎没有任何区别的真正原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.