回答:
ベクターに少なくとも3つのアイテムがある場合、最後の3つのアイテムを削除するのは簡単です。pop_backを 3回使用するだけです。
#include <vector>
#include <iostream>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 3 && !v.empty(); ++i)
v.pop_back();
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
}
出力:
1 2
まず、X.end()
イテレータをベクトルの最後の要素に戻さず、ベクトルの最後の要素を過ぎた要素にイテレータを戻します。これは、ベクトルが実際には所有していない要素です。そのため、X.erase(d)
プログラムのクラッシュでそれを消去します。
代わりに、ベクターに少なくとも3つの要素が含まれている場合、次の操作を実行できます。
X.erase( X.end() - 3, X.end() );
代わりに、最後から3番目の要素に移動し、その後に到達するまですべての要素を消去しX.end()
ます。
EDIT:だけを明確にするには、X.end()
あるLegacyRandomAccessIterator有効持つように指定されている-
別の返す操作LegacyRandomAccessIteratorを。
end()
from cppreferenceの定義は次のとおりです。
ベクトルコンテナー内の過去の最後の要素を参照する反復子を返します。
そして少し下:
それはいかなる要素も指さないので、逆参照されません。
つまり、ベクターにはend()が指す要素がありません。erase()メソッドを介してその非要素を逆参照することにより、ベクターに属していないメモリを変更している可能性があります。したがって、そこから醜いことが起こります。
間隔を[低、高)として記述するのは通常のC ++規則であり、「低」値は間隔に含まれ、「高」値は間隔から除外されます。
あなたは使うことができますreverse_iterator
:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<float> X = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
// start the iterator at the last element
vector<float>::reverse_iterator rit = X.rbegin();
// repeat 3 times
for(size_t i = 0; i < 3; i++)
{
rit++;
X.erase(rit.base());
}
// display all elements in vector X
for(float &e: X)
cout << e << '\n';
return 0;
}
言及すべきことがいくつかあります。
reverse_iterator rit
の最後の要素から始まりvector X
ます。この位置をと呼びrbegin
ます。erase
使用するにはクラシックiterator
が必要です。これはrit
、を呼び出すことで取得できbase
ます。しかし、その新しいイテレータはrit
、順方向から次の要素を指します。rit
電話をかける前にbase
、erase
質問のコメント(現在は削除済み)には、「イテレータの演算子はありません」とありました。ただし、次のコードのコンパイルと作品の両方でMSVC
とclang-cl
、標準セットのいずれかにC++17
かC++14
:
#include <iostream>
#include <vector>
int main()
{
std::vector<float> X{ 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f };
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
std::vector<float>::iterator d = X.end();
X.erase(d - 3, d); // This strongly suggest that there IS a "-" operator for a vector iterator!
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
return 0;
}
の定義operator-
は次のとおりです(<vector>
ヘッダー内):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
ただし、私は確かにC ++言語の弁護士ではありません。これは、これらの「危険な」Microsoft拡張機能の1つである可能性があります。これが他のプラットフォーム/コンパイラで動作するかどうか知りたいです。
-
、これらのタイプのイテレータに対して定義されているため、これは有効だと思います。
この文
if (i == 1) X.erase(d);
未定義の動作があります。
そして、このステートメントは最後の要素の前の要素のみを削除しようとします
else X.erase(d - i);
ループが2回しかないため
for (size_t i = 1; i < 3; i++) {
次のようなものが必要です。
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
auto n = std::min<decltype( v.size() )>( v.size(), 3 );
if ( n ) v.erase( std::prev( std::end( v ), n ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
プログラム出力は
1 2
d
は実際には存在しません。これは、の終わりを見つけるためにのみ使用できる、過去の終わりのカナリア値vector
です。削除することはできません。次に、イテレータを消去するとすぐに消えます。その後、を含め、何でも安全に使用することはできませんd - i
。