ฉันมีเวกเตอร์ ฉันต้องการลบองค์ประกอบ 3 ตัวสุดท้ายในนั้น อธิบายตรรกะนี้ โปรแกรมขัดข้อง มีข้อผิดพลาดอะไรบ้าง?
vector<float>::iterator d = X.end();
for (size_t i = 1; i < 3; i++) {
if (i == 1) X.erase(d);
else X.erase(d - i);
}
ฉันมีเวกเตอร์ ฉันต้องการลบองค์ประกอบ 3 ตัวสุดท้ายในนั้น อธิบายตรรกะนี้ โปรแกรมขัดข้อง มีข้อผิดพลาดอะไรบ้าง?
vector<float>::iterator d = X.end();
for (size_t i = 1; i < 3; i++) {
if (i == 1) X.erase(d);
else X.erase(d - i);
}
คำตอบ:
หากมีอย่างน้อย 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
มันเป็นพฤติกรรมที่ไม่ได้กำหนดไว้เพื่อส่งผ่านตัวend()
วนซ้ำไปยังerase()
โอเวอร์โหลด1 พารามิเตอร์ แม้ว่ามันจะไม่ได้erase()
เป็นโมฆะมันเป็นโมฆะที่ "ที่และหลัง" องค์ประกอบที่ระบุทำให้d
ไม่ถูกต้องหลังจากวนซ้ำที่ 1
std::vector
มีerase()
โอเวอร์โหลด2 พารามิเตอร์ที่ยอมรับช่วงขององค์ประกอบที่จะลบ คุณไม่จำเป็นต้องใช้ลูปด้วยตนเองเลย:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
อันดับแรกX.end()
ไม่ส่งคืนตัววนซ้ำไปยังองค์ประกอบสุดท้ายของเวกเตอร์ แต่จะส่งคืนตัววนซ้ำไปยังองค์ประกอบที่ผ่านองค์ประกอบสุดท้ายของเวกเตอร์ซึ่งเป็นองค์ประกอบที่เวกเตอร์ไม่มีตัวตนจริงนั่นคือสาเหตุที่เมื่อคุณพยายาม ลบด้วยX.erase(d)
โปรแกรมขัดข้อง
แต่หากเวกเตอร์มีองค์ประกอบอย่างน้อย 3 องค์ประกอบคุณสามารถทำสิ่งต่อไปนี้ได้:
X.erase( X.end() - 3, X.end() );
X.end()
ซึ่งแทนที่จะไปที่องค์ประกอบสุดท้ายที่สามและลบทุกองค์ประกอบหลังจากนั้นจนกว่าจะได้รับการ
แก้ไข: เพียงชี้แจงX.end()
เป็นLegacyRandomAccessIteratorซึ่งมีการระบุให้มีความถูกต้อง-
การดำเนินงานซึ่งจะส่งกลับอีกLegacyRandomAccessIterator
คำจำกัดความของend()
จากcppreferenceคือ:
ส่งคืนตัววนซ้ำหมายถึงองค์ประกอบที่ผ่านมาในภาชนะเวกเตอร์
และด้านล่างเล็กน้อย:
มันไม่ได้ชี้ไปที่องค์ประกอบใด ๆ และดังนั้นจะไม่ถูกยกเลิกการลงทะเบียน
กล่าวอีกนัยหนึ่งเวกเตอร์ไม่มีองค์ประกอบที่จุดสิ้นสุด () ชี้ไปที่ โดยการพิจารณาว่าไม่ใช่องค์ประกอบผ่านวิธีการลบ () คุณอาจจะเปลี่ยนหน่วยความจำที่ไม่ได้เป็นของเวกเตอร์ ดังนั้นสิ่งที่น่าเกลียดสามารถเกิดขึ้นได้จากที่นั่น
เป็นแบบแผน 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
นอกจากนี้หากคุณต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับreverse_iterator
ฉันขอแนะนำให้ไปที่คำตอบนี้
ความคิดเห็น (ถูกลบแล้ว) ในคำถามระบุว่า "ไม่มีตัวดำเนินการสำหรับตัววนซ้ำ" อย่างไรก็ตามรหัสต่อไปนี้รวบรวมและทำงานในทั้งสอง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;
}
อย่างไรก็ตามฉันไม่มีทนายความด้านภาษาซีพลัสพลัสและเป็นไปได้ว่านี่เป็นส่วนขยาย Microsoft หนึ่งในรายการ 'อันตราย' ฉันจะสนใจเป็นอย่างยิ่งที่จะทราบว่าสิ่งนี้ใช้ได้กับแพลตฟอร์ม / คอมไพเลอร์อื่น ๆ หรือไม่
-
ถูกกำหนดไว้สำหรับตัววนซ้ำชนิดนั้น
คำแถลงนี้
if (i == 1) X.erase(d);
มีพฤติกรรมที่ไม่ได้กำหนด
และคำสั่งนี้จะพยายามลบเฉพาะองค์ประกอบก่อนองค์ประกอบสุดท้าย
else X.erase(d - i);
เพราะคุณมีลูปที่มีการวนซ้ำสองครั้งเท่านั้น
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
คุณไม่สามารถได้อย่างปลอดภัยใช้งานได้หลังจากนั้นเพื่ออะไรรวมทั้ง