c ++ 11 lambdas จับตัวแปรที่ไม่ได้ใช้หรือไม่


124

เมื่อฉันใช้[=]เพื่อบ่งชี้ว่าผมอยากตัวแปรท้องถิ่นทั้งหมดจะถูกจับโดยค่าในแลมบ์ดาจะส่งผลให้ทุกตัวแปรท้องถิ่นในฟังก์ชั่นการคัดลอกหรือเพียงแค่ทุกตัวแปรท้องถิ่นที่ใช้โดยแลมบ์ดา ?

ตัวอย่างเช่นถ้าฉันมี:

vector<int> my_huge_vector(100000);
int my_measly_int;
some_function([=](int i){ return my_measly_int + i; });

my_huge_vector จะถูกคัดลอกหรือไม่แม้ว่าฉันจะไม่ได้ใช้ในแลมบ์ดา

คำตอบ:


115

ตัวแปรแต่ละตัวที่ตั้งชื่ออย่างชัดแจ้งในรายการจับภาพจะถูกบันทึก การจับค่าเริ่มต้นจะจับเฉพาะตัวแปรที่ทั้งสอง (a) ไม่ได้ระบุชื่อไว้อย่างชัดเจนในรายการจับภาพและ (b) ใช้ในเนื้อความของนิพจน์แลมบ์ดา หากไม่ได้ตั้งชื่อตัวแปรแบบชัดแจ้งและคุณไม่ได้ใช้ตัวแปรในนิพจน์แลมบ์ดาตัวแปรนั้นจะไม่ถูกบันทึก ในตัวอย่างของคุณmy_huge_vectorไม่ถูกบันทึก

ต่อ C ++ 11 §5.1.2 [expr.prim.lambda] / 11:

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

นิพจน์แลมบ์ดาของคุณมีค่าเริ่มต้นในการบันทึกที่เกี่ยวข้อง: โดยค่าเริ่มต้นคุณจะจับตัวแปรตามค่าโดยใช้[=].

ในกรณีที่มีการใช้ตัวแปร (ในความหมาย One Definition Rule ของคำว่า "used") เป็นตัวแปรที่จับโดยปริยาย เนื่องจากคุณไม่ได้ใช้my_huge_vectorเลยในร่างกาย ("คำสั่งประกอบ") ของนิพจน์แลมบ์ดาจึงไม่ถูกจับโดยปริยาย

เพื่อดำเนินการต่อด้วย§5.1.2 / 14

เอนทิตีถูกจับโดยสำเนา if

  • มันถูกจับโดยปริยายและค่าเริ่มต้นของการบันทึกคือ=หรือถ้า
  • มันถูกจับอย่างชัดเจนด้วยการจับภาพที่ไม่มี&ไฟล์.

เนื่องจากของคุณmy_huge_vectorไม่ได้ถูกจับโดยปริยายและไม่ได้ถูกจับอย่างชัดเจนจึงไม่ถูกจับโดยการคัดลอกหรืออ้างอิง


10
คุณมีข้อความศักดิ์สิทธิ์หรือไม่?
GManNickG

แต่ฉันจะบอกว่าทั้งหมดของ§5.1.2เป็นสิ่งสำคัญในการทำความเข้าใจรายละเอียดทั้งหมด มีคำศัพท์ทางเทคนิคจำนวนมากที่กำหนดไว้ในส่วนนั้นและเนื่องจากคำจำกัดความของส่วนประกอบต่างๆของนิพจน์แลมบ์ดาจำเป็นต้องมีความยุ่งเหยิงจึงเป็นเรื่องยากที่จะดึงเครื่องหมายคำพูดสั้น ๆ ที่บอกว่า "นี่คือ X และนี่คือสาเหตุที่ X"
James McNellis

ขอความสนใจของคุณที่นี่ซึ่งระบุว่าไม่อนุญาตให้เพิ่มประสิทธิภาพดังกล่าวอย่างน้อยสำหรับตัวแปรที่มีชื่อชัดเจน ฉันไม่แน่ใจว่าจะลากเส้นตรงไหน
GManNickG

@GManNickG: นั่นคือการหลอกล่อที่ดี ;-) ฉันต้องใช้เวลาคลิกลิงค์นั้นสามครั้งก่อนที่ฉันจะรู้ว่ามันชี้ไปที่หน้านี้จริงๆ ... : -O [ไม่ว่าในกรณีใดฉันจะอ่านข้อกำหนดภาษาอีกครั้งเมื่อฉันเข้าสำนักงานพรุ่งนี้เช้าและอัปเดต คำตอบที่เหมาะสม]
James McNellis

โอ้โหขอโทษ !!! คำถามของฉันได้รับคำตอบฉันตั้งใจจะเชื่อมโยงที่นี่แทน นั่นคงทำให้สับสนอย่างมาก
GManNickG

16

ไม่my_huge_vectorจะไม่ถูกจับ [=]หมายความว่าตัวแปรที่ใช้ทั้งหมดถูกจับไว้ในแลมด้า


6
อ๋อ โปรดทราบว่าคำที่ใช้เป็นคำทางเทคนิคและหมายถึงกฎความหมายเดียวที่ใช้จริงๆ void f() { const int size(10); [] { int x[size]; }; }ดังนั้นสำหรับตัวอย่างเช่นพิจารณา ที่นี่sizeไม่ได้จับภาพ แต่ไม่เป็นไรเพราะไม่ได้ใช้ในความหมาย ODR (Visual C ++ 2010 ไม่ยอมรับรหัสนี้ไม่ว่าจะเป็นเพราะข้อมูลจำเพาะเปลี่ยนแปลงไปหลังจากที่ VC10 ถูกปล่อยออกมาหรือเกิดจากข้อผิดพลาดซึ่งน่าจะได้รับการแก้ไขในเวอร์ชันที่กำลังจะมีขึ้น g ++ 4.5.1 ยอมรับ)
James McNellis

@JamesMcNellis dp ไม่ต้องกังวล MSVC ยังคงเป็นกองขยะที่มีกลิ่นเหม็นในวันนี้ cf เลย godbolt.org/z/vHnnCX (ตรวจสอบ gcc สำหรับ lulz) ที่กล่าวว่า; ฉันไม่เข้าใจว่าเหตุใดตัวระบุใด ๆ ที่ปรากฏในนิพจน์ที่ประเมินจึงไม่ใช้ ODR ฉันคิดว่ากรณีนี้ใช้ ODR อย่างแน่นอนเว้นแต่คุณจะหมายถึงสามารถตีความเป็น constexpr ได้ดังนั้นค่าเท่านั้นจึงมีประโยชน์? ฉันไม่แน่ใจว่าคอมไพเลอร์สันนิษฐานว่าconstสิ่งต่างๆไม่อาจกลายพันธุ์ เว้นแต่ว่าการเพิ่มประสิทธิภาพที่เข้มงวดมากอาจตั้งค่าสถานะ OX หรือสิ่งของ
v.oddou
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.