วนรอบตาม C ++ 11: รับไอเท็มตามค่าหรืออ้างอิงถึง const


215

การอ่านตัวอย่างของลูปแบบช่วงพวกเขาแนะนำสองวิธีหลัก1 , 2 , 3 , 4

std::vector<MyClass> vec;

for (auto &x : vec)
{
  // x is a reference to an item of vec
  // We can change vec's items by changing x 
}

หรือ

for (auto x : vec)
{
  // Value of x is copied from an item of vec
  // We can not change vec's items by changing x
}

ดี.

เมื่อเราไม่ต้องการเปลี่ยนvecไอเท็ม IMO ตัวอย่างแนะนำให้ใช้เวอร์ชันที่สอง (ตามค่า) ทำไมพวกเขาไม่แนะนำสิ่งที่constอ้างอิง (อย่างน้อยฉันไม่พบข้อเสนอแนะโดยตรง):

for (auto const &x : vec) // <-- see const keyword
{
  // x is a reference to an const item of vec
  // We can not change vec's items by changing x 
}

มันจะดีกว่าไหม มันหลีกเลี่ยงสำเนาที่ซ้ำซ้อนในการทำซ้ำแต่ละครั้งconstหรือไม่

คำตอบ:


390

หากคุณไม่ต้องการเปลี่ยนรายการรวมทั้งต้องการหลีกเลี่ยงการทำสำเนานี่auto const &คือตัวเลือกที่ถูกต้อง:

for (auto const &x : vec)

ใครแนะนำให้คุณใช้auto &ผิด ไม่สนใจพวกเขา

นี่คือสรุป:

  • เลือกauto xเมื่อคุณต้องการทำงานกับสำเนา
  • เลือกauto &xเมื่อคุณต้องการทำงานกับรายการต้นฉบับและอาจแก้ไขได้
  • เลือกauto const &xเมื่อคุณต้องการทำงานกับรายการต้นฉบับและจะไม่แก้ไข

21
ขอบคุณสำหรับคำตอบที่ดี ฉันเดาว่าควรชี้ให้เห็นว่าconst auto &xเทียบเท่ากับทางเลือกที่สามของคุณ
smg

7
@mloskot: มันเทียบเท่า (และทำในสิ่งที่คุณหมายถึงโดย"แต่มันเป็นเรื่องไวยากรณ์เดียวกัน"ไวยากรณ์ที่แตกต่างกัน observably?.)
นาวาซ

14
ไม่มี: auto&&เมื่อคุณไม่ต้องการทำสำเนาที่ไม่มีความจำเป็นและไม่สนใจว่าคุณจะแก้ไขหรือไม่และคุณต้องการทำงาน
Yakk - Adam Nevraumont

4
ความแตกต่างของการอ้างอิงใช้กับสำเนาหรือไม่หากคุณเพิ่งทำงานกับประเภทพื้นฐานเช่น int / double

4
@ ประเมิน: ฉันไม่สามารถแสดงความคิดเห็นเกี่ยวกับความเร็วโดยรวมและฉันคิดว่าไม่มีใครสามารถทำได้โดยไม่ต้องทำโปรไฟล์ก่อน ตรงไปตรงมาฉันจะไม่เลือกความเร็วตามความต้องการของฉันเลย ถ้าฉันต้องการความไม่สามารถเปลี่ยนแปลงได้ฉันจะใช้อย่างconstแน่นอน อย่างไรก็ตามไม่ว่ามันจะเป็นauto const &หรือauto const มีความแตกต่างเล็กน้อย ฉันเลือกauto const &ที่จะสอดคล้องกันมากขึ้น
นาวาซ

23

หากคุณมีstd::vector<int>หรือstd::vector<double>ก็แค่ใช้auto(พร้อมสำเนาค่า) แทนconst auto&เนื่องจากคัดลอกintหรือมีdoubleราคาถูก:

for (auto x : vec)
    ....

แต่ถ้าคุณมีstd::vector<MyClass>, ซึ่งMyClassมีความหมายบางสำเนาที่ไม่สำคัญ (เช่นstd::string, คลาสที่กำหนดเองที่ซับซ้อน, ฯลฯ ) ดังนั้นฉันขอแนะนำให้ใช้const auto&เพื่อหลีกเลี่ยงสำเนาลึก :

for (const auto & x : vec)
    ....

3

เมื่อเราไม่ต้องการเปลี่ยนvecรายการตัวอย่างแนะนำให้ใช้รุ่นแรก

จากนั้นพวกเขาให้คำแนะนำที่ผิด

ทำไมพวกเขาไม่แนะนำสิ่งที่อ้างอิง const

เพราะพวกเขาให้คำแนะนำที่ผิด :-) สิ่งที่คุณพูดถึงนั้นถูกต้อง หากคุณตองการสังเกตวัตถุเทานั้นไมตองสรางสําเนาและไมตองมีวัตถุที่ไมใชconstอ้างอิงถึงวัตถุนั้น

แก้ไข:

ฉันเห็นการอ้างอิงที่คุณเชื่อมโยงทั้งหมดให้ตัวอย่างของการวนซ้ำในช่วงของintค่าหรือประเภทข้อมูลพื้นฐานอื่น ๆ ในกรณีที่ว่าตั้งแต่คัดลอกintไม่แพง, การสร้างสำเนาเป็นพื้นเทียบเท่า (ถ้าไม่ได้มีประสิทธิภาพมากขึ้นกว่า) const &มีการสังเกต

อย่างไรก็ตามนี่ไม่ใช่กรณีทั่วไปสำหรับประเภทที่ผู้ใช้กำหนด UDTs อาจจะแพงเพื่อคัดลอกและถ้าคุณไม่ได้มีเหตุผลสำหรับการสร้างสำเนา (เช่นการปรับเปลี่ยนวัตถุที่ดึงโดยไม่ต้องเปลี่ยนเดิม) const &แล้วมันจะดีกว่าที่จะใช้


1

ฉันจะตรงข้ามกับที่นี่และบอกว่าไม่จำเป็นต้องauto const &อยู่ในช่วงที่ใช้ลูป บอกฉันว่าคุณคิดว่าฟังก์ชั่นต่อไปนี้มันงี่เง่า (ไม่ใช่ในจุดประสงค์ของมัน แต่ในแบบที่เขียน)

long long SafePop(std::vector<uint32_t>& v)
{
    auto const& cv = v;
    long long n = -1;
    if (!cv.empty())
    {
        n = cv.back();
        v.pop_back();
    }
    return n;
}

ที่นี่ผู้เขียนได้สร้างการอ้างอิง const ที่vจะใช้สำหรับการดำเนินการทั้งหมดซึ่งไม่ได้แก้ไข v นี่คือความโง่ในความคิดของฉันและอาร์กิวเมนต์เดียวกันสามารถทำเพื่อใช้auto const &เป็นตัวแปรในช่วงที่ใช้สำหรับวนรอบแทนเพียงauto &.


3
@BenjaminLindley: ดังนั้นฉันสามารถสรุปได้ว่าคุณจะเถียงconst_iteratorในวง? คุณจะมั่นใจได้อย่างไรว่าคุณไม่ได้เปลี่ยนไอเท็มดั้งเดิมจากคอนเทนเนอร์เมื่อมันวนซ้ำไปมา?
Nawaz

2
@BenjaminLindley: ทำไมรหัสของคุณถึงไม่คอมไพล์const_iterator? ให้ฉันเดาว่าคอนเทนเนอร์ที่คุณวนซ้ำมันคือconstอะไร แต่ทำไมconstต้องเริ่มด้วย ที่ไหนที่คุณใช้constเพื่อให้แน่ใจว่ามีอะไร
Nawaz

8
ข้อได้เปรียบของการทำวัตถุconstก็เหมือนข้อดีของการใช้private/ protectedในชั้นเรียน มันหลีกเลี่ยงข้อผิดพลาดเพิ่มเติม
masoud

2
@BenjaminLindley: โอ้ฉันมองข้ามไป จากนั้นในกรณีนี้การใช้งานก็โง่เช่นกัน แต่ถ้าฟังก์ชั่นนั้นไม่ได้ปรับเปลี่ยนvการใช้งานก็น่าจะใช้ได้ และถ้าห่วงไม่เคยปรับเปลี่ยนวัตถุมัน iterates constผ่านดูเหมือนขวาให้ฉันที่จะมีการเตะไป ฉันเห็นประเด็นของคุณแล้ว ของฉันคือลูปแสดงถึงรหัสหน่วยที่คล้ายกับฟังก์ชั่นและภายในหน่วยนั้นไม่มีคำสั่งที่จำเป็นต้องแก้ไขค่า ดังนั้นคุณสามารถ "แท็ก" หน่วยทั้งหมดเช่นconstเดียวกับที่คุณทำกับconstฟังก์ชั่นสมาชิก
Andy Prowl

1
ดังนั้นคุณคิดว่าconst &สำหรับช่วงอิงเป็นโง่เพราะคุณเขียนตัวอย่างจินตภาพที่ไม่เกี่ยวข้องของโปรแกรมเมอร์ในจินตนาการที่ทำอะไรโง่ ๆ ด้วยCV -คุณสมบัติ? ... ตกลงแล้ว
underscore_d
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.