C ++ STL Vectors: รับตัววนซ้ำจากดัชนีหรือไม่


200

ดังนั้นฉันจึงเขียนโค้ดที่เข้าถึงองค์ประกอบใน stl เวกเตอร์โดย index [] แต่ตอนนี้ฉันต้องคัดลอกอันของเวกเตอร์ ดูเหมือนว่าvector.insert(pos, first, last)เป็นฟังก์ชั่นที่ฉันต้องการ ... ยกเว้นฉันจะมีครั้งแรกและครั้งสุดท้ายเป็น ints มีวิธีที่ดีที่ฉันสามารถใช้ตัววนซ้ำตามค่าเหล่านี้หรือไม่?


1
ดูเพิ่มเติมที่: stackoverflow.com/q/2152986/365102
Mateen Ulhaq

หากฉันไม่ผิดไม่มีคำตอบใดที่ตรวจสอบขอบเขตซึ่งอาจเป็นปัญหา โดยเฉพาะ std :: advance docs บอกว่าพฤติกรรมนั้นไม่ได้ถูกกำหนดถ้าคุณใช้มันเพื่อผ่านขอบเขตคอนเทนเนอร์พื้นฐาน
Martin Pecka

คำตอบ:


293

ลองสิ่งนี้:

vector<Type>::iterator nth = v.begin() + index;

4
โดยทั่วไปคุณสามารถใช้เลขคณิตเดียวกันกับตัววนซ้ำ STL ได้มากกว่าตัวชี้ พวกมันถูกออกแบบมาให้สามารถแลกเปลี่ยนได้เมื่อใช้อัลกอริธึม STL
Vincent Robert

18
@VincentRobert: วิธีอื่น ๆ พอยน์เตอร์เป็นการนำไปใช้ที่ถูกต้องของตัววนซ้ำแบบสุ่มของ STL ซึ่งเป็นหมวดที่ทรงพลังที่สุด แต่หมวดหมู่อื่น ๆ ที่มีประสิทธิภาพน้อยกว่าเช่นตัววนไปข้างหน้าไม่สนับสนุนเลขคณิตเดียวกัน
MSalters

6
ฉันต้องการ ot เพิ่มห้าเซ็นต์ของฉันในคำตอบนี้และแนะนำstd::next(v.begin(), index)
stryku

87

วิธีที่กล่าวถึงโดย @dirkgently ( v.begin() + index )ดีและรวดเร็วสำหรับเวกเตอร์

แต่วิธีทั่วไปที่สุดและสำหรับตัววนซ้ำการเข้าถึงแบบสุ่มก็ใช้เวลาคงที่เช่นกัน std::advance( v.begin(), index )


ความแตกต่างของการแก้ไขในการใช้งาน:

std::vector<>::iterator it = ( v.begin() + index );

หรือ

std::vector<>::iterator it = v.begin();
std::advance( it, index );

เพิ่มหลังจากบันทึก @litb


ไม่ std :: advance ต้องการตัววนซ้ำที่ไม่ใช่ const เป็นอาร์กิวเมนต์แรก
goldPseudo

คุณสามารถใช้มาตรฐาน :: ล่วงหน้า const และไม่ const iterators
Bayda

1
คุณไม่ควรเชื่อถือ msvc ในเรื่องนั้น มันมีส่วนขยายที่ไม่ได้มาตรฐานที่ทำให้มันยอมรับสิ่งนี้อย่างไรก็ตามคอมไพเลอร์อื่น ๆ ทั้งหมดประพฤติตามมาตรฐานและปฏิเสธมัน
Johannes Schaub - litb

1
ฉันคิดว่าปัญหาคือความสับสนในความหมายของ "const": advance () อย่างมีความสุขจะทำงานกับ const_iterator <T> ซึ่งเป็นตัววนซ้ำที่ไม่แน่นอนที่อ้างถึงองค์ประกอบ const ของประเภท T; มันจะไม่ทำงานกับวัตถุตัววนซ้ำซึ่งเป็นตัวเอง const (เช่น "const iterator <T>" หรือ "iterator <T> const")
j_random_hacker

7
ถ้าคุณรู้ว่าคุณกำลังติดต่อกับมีจุดในการใช้ไม่มีstd::vector std::advanceมันหลอกล่อให้คุณคิดว่าคุณกำลังเขียนโค้ดที่ไม่เชื่อเรื่องพระเจ้า (ซึ่งคุณทำไม่ได้คิดถึงกฎการตรวจสอบความถูกต้องตัววนซ้ำตัววนซ้ำความซับซ้อนรันไทม์ที่แตกต่างกันและอะไรก็ตาม) กรณีเดียวที่std::advanceเหมาะสมเมื่อคุณเขียนเทมเพลตด้วยตัวเองซึ่งไม่ทราบว่าเป็นตัววนซ้ำที่เกี่ยวข้องกับอะไร
Frerich Raabe

47

นอกจากนี้ยัง; auto it = std::next(v.begin(), index);

อัปเดต: ต้องมีคอมไพเลอร์ที่สอดคล้องกับ C ++ 11x


2
ควรสังเกตว่านี่คือวิธี C ++ 11! std :: next เทียบเท่ากับ std :: advance การใช้ฟังก์ชั่นเหล่านี้แทนที่จะใช้ arithmetics ทำให้การสลับประเภทคอนเทนเนอร์ง่ายขึ้นมาก แม้ทำงานบน c-arrays afaik ก็เหมือนกับ std :: start และ std :: end
Zoomulator

2
ควรสังเกตว่า std :: advance ถูกออกแบบโดยคนงี่เง่าเนื่องจากใช้การอ้างอิงเป็นเอาต์พุตไม่ใช่ค่าส่งคืน
Viktor Sehr

1
สำหรับ (auto it = เริ่มต้น (c); it! = end (c); advance (it, n)) {... }
Zoomulator

2
ทั้งสองมีประโยชน์ stda :: advance มีประโยชน์สำหรับการเปลี่ยน iterator ให้เข้าที่ มันเป็นเรื่องของประสิทธิภาพในลูป ฉันต้องการสิ่งต่อไปในกรณีของการมอบหมายตามที่คุณแนะนำ ฉันเพิ่งพบว่ามันรุนแรงเล็กน้อยโดยอ้างว่ามันเป็นคนงี่เง่า ฟังก์ชั่นทั้งสองได้รับการออกแบบโดยคำนึงถึงสถานการณ์ที่แตกต่างกันถึงแม้ว่าโดยทั่วไปแล้วจะเป็นแบบเดียวกันก็ตาม
Zoomulator

5
@Zoomulator: หากการคัดลอกตัววนซ้ำเป็นเรื่องเกี่ยวกับประสิทธิภาพคุณมีปัญหาที่ใหญ่กว่าที่จะจัดการ
Mooing Duck


-3

Actdally std :: vector ใช้เพื่อเป็นแท็บ C เมื่อต้องการ (คำขอมาตรฐาน C ++ สำหรับการใช้งานเวกเตอร์เท่าที่ฉันรู้ - การแทนที่อาเรย์ใน Wikipedia ) ตัวอย่างเช่นมันถูกกฎหมายอย่างสมบูรณ์แบบที่จะทำสิ่งนี้ตามที่ฉัน:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

แน่นอนว่าทั้ง foo จะต้องไม่คัดลอกที่อยู่ที่ส่งผ่านเป็นพารามิเตอร์และเก็บไว้ที่อื่นหรือคุณควรตรวจสอบให้แน่ใจในโปรแกรมของคุณว่าอย่ากดรายการใหม่ใด ๆ ใน vec หรือร้องขอให้เปลี่ยนความจุของมัน หรือแบ่งส่วนความเสี่ยง ...

ดังนั้นในตัวอย่างของคุณมันนำไปสู่

vector.insert(pos, &vec[first_index], &vec[last_index]);

ทำให้ฉันสงสัยว่าทำไมพวกเขาตัดสินใจที่จะสรุปให้ผู้ทำซ้ำหากพวกมันเป็นเพียงตัวชี้ ... พวกเขา "ซ่อน" ความสามารถเหล่านี้
mpen

เพื่อความสอดคล้อง? มันจะช่วยให้คุณสามารถลบอินสแตนซ์ของเวกเตอร์สำหรับคอนเทนเนอร์ชนิดอื่นในโค้ดของคุณได้อย่างง่ายดาย
yves Baumes

4
& vec [i] ให้ตัวชี้ซึ่งไม่จำเป็นต้องเข้ากันได้กับเวกเตอร์ <> :: iterator vec.begin () + ฉันยังคงมีประโยชน์ในการเป็นตัวทำซ้ำสิ่งที่ห้องสมุดของคุณกำหนดให้เป็น - รวมถึงตัวตรวจสอบซ้ำในโหมดการแก้ปัญหาเช่น ดังนั้นหากคุณไม่ต้องการตัวชี้ (เช่น I / O) คุณควรเลือกตัววนซ้ำเสมอ
sellibitze

@KerrekSB จาก 23.3.6.1 ในร่างมาตรฐาน c ++: "องค์ประกอบของเวกเตอร์ถูกจัดเก็บไว้อย่างต่อเนื่องซึ่งหมายความว่าถ้า v เป็นเวกเตอร์ <T, Allocator> โดยที่ T เป็นประเภทอื่นที่ไม่ใช่ bool แล้วก็เชื่อฟังเอกลักษณ์ & v [ n] == & v [0] + n สำหรับทั้งหมด 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes: ไม่มีส่วนเกี่ยวข้องกับตัววนซ้ำของเวกเตอร์ อย่างไรก็ตามมันเป็นความจริงที่พอยน์เตอร์เปล่านั้นเป็นตัววนซ้ำ - มันไม่ใช่เวกเตอร์ตัววนซ้ำ
Kerrek SB
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.