อะไรคือความแตกต่างระหว่าง a const_iterator
และ an iterator
และคุณจะใช้อีกอันหนึ่งตรงไหน
อะไรคือความแตกต่างระหว่าง a const_iterator
และ an iterator
และคุณจะใช้อีกอันหนึ่งตรงไหน
คำตอบ:
const_iterator
s ไม่อนุญาตให้คุณเปลี่ยนค่าที่พวกเขาชี้ไปปกติiterator
s ทำ
เช่นเดียวกับทุกสิ่งใน C ++ ควรเลือกใช้เสมอconst
เว้นแต่จะมีเหตุผลที่ดีในการใช้ตัวทำซ้ำปกติ (เช่นคุณต้องการใช้ข้อเท็จจริงที่ว่าพวกเขาจะไม่const
เปลี่ยนค่าชี้ไป)
พวกเขาควรจะอธิบายตัวเองได้ดีทีเดียว หากตัววนรอบชี้ไปที่องค์ประกอบประเภท T ดังนั้น const_iterator จะชี้ไปที่องค์ประกอบประเภท 'const T'
โดยพื้นฐานแล้วมันเทียบเท่ากับประเภทตัวชี้:
T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator
ตัววนซ้ำ const ชี้ไปที่องค์ประกอบเดียวกันเสมอดังนั้นตัววนซ้ำจึงเป็น const แต่องค์ประกอบที่ชี้ไปนั้นไม่จำเป็นต้องเป็น const ดังนั้นองค์ประกอบที่ชี้ว่าสามารถเปลี่ยนแปลงได้ const_iterator คือตัววนซ้ำที่ชี้ไปยังองค์ประกอบ const ดังนั้นในขณะที่ตัววนซ้ำสามารถอัปเดตได้ (เพิ่มขึ้นหรือลดลงเป็นต้น) องค์ประกอบที่ชี้ไปนั้นไม่สามารถเปลี่ยนแปลงได้
const iterater
และconst_iterator
.
โชคไม่ดีที่วิธีการมากมายสำหรับคอนเทนเนอร์ STL ใช้ตัวทำซ้ำแทนที่จะใช้const_iteratorsเป็นพารามิเตอร์ ดังนั้นหากคุณมีconst_iteratorคุณจะไม่สามารถพูดว่า "แทรกองค์ประกอบก่อนองค์ประกอบที่ตัววนซ้ำนี้ชี้ไป" (การบอกว่าสิ่งนั้นไม่ได้เป็นการละเมิดแนวคิดในความคิดในความคิดของฉัน) หากคุณต้องการทำต่อไปที่คุณจะต้องแปลงเป็น iterator ไม่ใช่ const ใช้มาตรฐาน :: ล่วงหน้า ()หรือเพิ่ม :: ถัดไป () เช่น. เพิ่ม :: ถัดไป (container.begin () มาตรฐาน :: ระยะทาง (container.begin () the_const_iterator_we_want_to_unconst)) ถ้าภาชนะที่เป็นมาตรฐาน :: รายการแล้วเวลาทำงานสำหรับการโทรที่จะเป็นO (n)
ดังนั้นกฎสากลในการเพิ่ม const ไม่ว่าจะเป็น "ตรรกะ" ในการทำเช่นนั้นจึงมีความเป็นสากลน้อยกว่าเมื่อพูดถึงคอนเทนเนอร์ STL
อย่างไรก็ตามบูสต์คอนเทนเนอร์ใช้ const_iterators (เช่น boost :: unordered_map :: erase ()) ดังนั้นเมื่อคุณใช้บูสต์คอนเทนเนอร์คุณจะ "บีบรัด" ได้ ยังไงก็ตามใครทราบหรือไม่ว่าคอนเทนเนอร์ STL จะได้รับการแก้ไขหรือไม่?
vector
และdeque
ใส่องค์ประกอบหนึ่งเลิก iterators const
ที่มีอยู่ทั้งหมดซึ่งไม่มาก แต่ฉันเห็นประเด็นของคุณ การดำเนินการดังกล่าวได้รับการปกป้องโดย container const
-ness ไม่ใช่ตัวทำซ้ำ และฉันสงสัยว่าทำไมไม่มีฟังก์ชันการแปลงตัววนซ้ำ const-to-nonconst ในอินเทอร์เฟซคอนเทนเนอร์มาตรฐาน
int const * foo;
int * const foo;
และint const * const foo;
ทั้งสามอย่างนั้นถูกต้องและมีประโยชน์โดยแต่ละอย่างมีวิธีการของตัวเอง std::vector<int> const bar
ควรจะเหมือนกับอันที่สอง แต่น่าเสียดายที่มักจะถือว่าเหมือนอันที่สาม ต้นตอของปัญหาคือเราไม่สามารถบอกได้ว่าstd::vector<int const> bar;
เมื่อไหร่หมายความว่าไม่มีทางที่จะได้รับผลเช่นเดียวint const *foo;
กับเวกเตอร์
ใช้const_iteratorทุกครั้งที่ทำได้ใช้iteratorเมื่อคุณไม่มีทางเลือกอื่น
ตัวอย่างที่รันได้น้อยที่สุด
ตัวทำซ้ำที่ไม่เป็นองค์ประกอบทำให้คุณสามารถแก้ไขสิ่งที่ชี้ไปที่:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);
ตัววนซ้ำคงไม่:
const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
ดังที่แสดงไว้ด้านบนv.begin()
มีการconst
โอเวอร์โหลดและส่งกลับอย่างใดอย่างหนึ่งiterator
หรือconst_iterator
ขึ้นอยู่กับ const-ness ของตัวแปร container:
กรณีทั่วไปที่const_iterator
ป๊อปอัปคือเมื่อthis
ใช้ภายในconst
เมธอด:
class C {
public:
std::vector<int> v;
void f() const {
std::vector<int>::const_iterator it = this->v.begin();
}
void g(std::vector<int>::const_iterator& it) {}
};
const
ทำให้this
const ซึ่งทำให้this->v
const
โดยปกติคุณสามารถลืมมันได้auto
แต่ถ้าคุณเริ่มส่งผ่านตัวทำซ้ำเหล่านั้นคุณจะต้องนึกถึงลายเซ็นวิธีการเหล่านั้น
เช่นเดียวกับ const และ non-const คุณสามารถแปลงจาก non-const เป็น const ได้อย่างง่ายดาย แต่ไม่ใช่วิธีอื่น:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
// non-const to const.
std::vector<int>::const_iterator cit = it;
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
// Compile time error: no conversion from const to no-const.
//it = ci1;
จะใช้ตัวไหนดี: คล้ายกับconst int
vs int
: ชอบตัวทำซ้ำ const เมื่อใดก็ตามที่คุณสามารถใช้งานได้ (เมื่อคุณไม่จำเป็นต้องแก้ไขคอนเทนเนอร์ด้วย) เพื่อบันทึกความตั้งใจในการอ่านได้ดีขึ้นโดยไม่ต้องแก้ไข
(ตามที่คนอื่นพูด) const_iterator ไม่อนุญาตให้คุณแก้ไของค์ประกอบที่มันชี้สิ่งนี้มีประโยชน์ในเมธอดคลาส const นอกจากนี้ยังช่วยให้คุณสามารถแสดงเจตนาของคุณ
ตกลงให้ฉันอธิบายด้วยตัวอย่างง่าย ๆ ก่อนโดยไม่ต้องใช้ตัววนซ้ำคงที่ถือว่าเรามีคอลเลกชันของจำนวนเต็มสุ่มคอลเลกชัน "randomData"
for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;
ดังที่เห็นได้สำหรับการเขียน / แก้ไขข้อมูลภายในคอลเลกชันตัววนซ้ำปกติถูกใช้ แต่สำหรับการอ่านตัววนซ้ำค่าคงที่ถูกใช้ หากคุณลองใช้ตัววนซ้ำแบบคงที่ในครั้งแรกสำหรับการวนซ้ำคุณจะได้รับข้อผิดพลาด ตามกฎทั่วไปให้ใช้ตัววนซ้ำแบบคงที่เพื่ออ่านข้อมูลภายในคอลเลกชัน