[英]Reducing the size of a std::vector without a default constructor
我有一個使用std::vector
模板參數的模板化類。 該參數可能不是默認可構造的。 我想減小向量的大小(將其切成給定的大小)。 明顯地
vec.resize( reduced_size );
...不起作用,因為它需要默認構造函數。
我當然可以:
在寫這個問題時,我注意到我可以從向量中erase
元素直到最后:
vec.erase ( vec.begin() + position, vec.end() );
...但是,我不確定這是否與resize
一樣有效。
有沒有一種有效的方法可以在沒有默認構造函數的情況下減小向量的大小?
C++11 解決方案是可以接受的。
編輯:似乎 MSVC 和 GCC 都將縮小調整大小作為擦除調用來實現,因此可以回答我的性能問題。
您使用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 );
在我的實現中,看起來我們有(有一些簡化):
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
的效果。 我猜想編譯器很難或不可能從v.resize(sz)
優化_M_default_append
調用,但在v.erase(iter, v.end())
中相對容易注意到__last == end()
並優化掉_GLIBCXX_MOVE3
和+ (end() - __last)
。 所以這里的erase()
很可能比resize()
更有效。
我希望大多數實現都是一個類似的故事:一些簡單的if
測試,然后調用一些相同的方法來調用最后元素的析構函數。
當然 - 當您調用resize
,您可以提供第二個參數傳遞正確類型的值,如果您使用resize
來增加向量的大小,該值將(理論上)用於填充空位。 在 C++03 中,該參數的默認值為T()
,這是默認構造函數出現的地方(在 C++11 中,它們使用重載代替,因此您可以調用resize()
來減小大小而無需任何進一步的困難)。
通過傳遞您自己的值,您可以避免使用默認構造函數。 如上所述,在 C++11 中,即使您不傳遞第二個參數,也不需要/使用默認的構造函數。
我懷疑與使用erase
相比,這會帶來任何真正的改進。 特別是,標准中的規范是(§23.3.6.3/9):
如果
sz <= size()
,相當於erase(begin() + sz, end());
.
因此,在這種情況下, resize
和erase
之間似乎沒有任何區別的真正原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.