尝试编写一个从std :: map中删除第一个(最低键)N项的方法。试过这个:
void EraseNMapElements(const int numElementsToRemove){
const int originalSize = _map.size();
auto eraseIter = _map.begin();
std::advance(eraseIter, numElementsToRemove);
_map.erase(_map.begin(), eraseIter);
assert(_map.size() == (originalSize - numElementsToRemove)) || (0 == originalSize) || (0 == _map.size()));
}
当元素数量超过请求删除的数量时,它可以工作。因此,如果我有五个元素,请求删除2,最后3个元素仍然存在。但是,如果我有一个元素并请求擦除2,我仍然有一个元素。
有没有巧妙的方法来解决这个问题?我可以围绕检查numElementsToRemove大于map.size()来推送IF语句,但必须有更好的解决方案吗?
答案 0 :(得分:4)
std::advance(i, n)
的前提条件是i
可以增加至少n
次。在您的代码中,您没有检查该前置条件,因此如果您使用numElementsToRemove > originalSize
调用它,则会违反该前提条件,从而遇到未定义的行为。要解决此问题,您必须在调用std::advance
之前进行检查,可能使用std::min
:
auto realNumToRemove = std::min(numElementsToRemove, originalSize);
std::advance(eraseIter, realNumToRemove);
答案 1 :(得分:4)
if
语句提供了一个简单易读的解决方案:
if (originalSize <= numElementsToRemove) {
auto eraseIter = _map.begin();
std::advance(eraseIter, numElementsToRemove);
_map.erase(_map.begin(), eraseIter);
} else {
_map.clear(); // or whatever's appropriate
}
答案 2 :(得分:3)
有一件事尚未被提及,而且值得一提的是,因为C ++ 11 std :: map :: erase(const_iterator)实际上将迭代器返回到以下元素。所以代码也可以写成:
function woo_override_checkout_fields( $fields ) {
$fields['shipping']['shipping_country'] = array(
'type' => 'select',
'required'=>true,
'label' => __('Country', 'shop'),
'options' => getAllowedCountries()
);
$fields['billing']['billing_country'] = array(
'type' => 'select',
'required'=>true,
'label' => __('Country', 'shop'),
'options' => getAllowedCountries()
);
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'woo_override_checkout_fields' );
这将遍历元素以擦除一次而不是两次。
答案 3 :(得分:1)
我能看到的最简单的方法是使用std::next
和if语句。
void EraseNMapElements(const int numElementsToRemove)
{
if (_map.size() < numElementsToRemove)
_map.erase(_map.begin(), std::next(_map.begin(), numElementsToRemove));
else
_map.clear();
}
请注意_map.size() < numElementsToRemove
有符号/无符号不匹配。 numElementsToRemove
最好是std::size_t
或decltype(_map)::size_type
。