C ++ auto & vs auto


91

เมื่อสร้างตัวแปรท้องถิ่นใช้ถูกต้อง(const) auto&หรือautoไม่?

เช่น:

SomeClass object;
const auto result = object.SomeMethod();

หรือ const auto& result = object.SomeMethod();

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

สิ่งที่เกี่ยวกับประเภทดั้งเดิม? ฉันถือว่าconst auto sum = 1 + 2;ถูกต้อง

สิ่งนี้ใช้กับช่วงที่อิงกับลูปด้วยหรือไม่

for(const auto& object : objects)

1
ฉันขอแนะนำให้คุณอ่านสิ่งนี้: safaribooksonline.com/library/view/effective-modern-c/…สองบทแรกไม่มีค่าใช้จ่ายและอธิบายการหักประเภทเทมเพลตซึ่งโดยพื้นฐานแล้วเป็นอย่างไรauto(ยกเว้นกรณีเฉพาะของinitializer_lists ซึ่ง ได้แก่ ไม่อนุมานในบริบทเทมเพลต) จากนั้นautoพิมพ์การหักลบ
vsoftco

คำตอบ:


107

autoและauto &&ครอบคลุมกรณีส่วนใหญ่:

  • ใช้autoเมื่อคุณต้องการสำเนาในเครื่อง สิ่งนี้จะไม่สร้างข้อมูลอ้างอิง ต้องมีตัวสร้างการคัดลอก (หรือย้าย) แต่อาจไม่ถูกเรียกเนื่องจากการเพิ่มประสิทธิภาพการคัดลอกสำเนา

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

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

auto &และauto const &มีความเฉพาะเจาะจงมากขึ้นเล็กน้อย:

  • auto &รับประกันว่าคุณกำลังแชร์ตัวแปรกับอย่างอื่น เป็นข้อมูลอ้างอิงเสมอและไม่ใช้ชั่วคราว

  • auto const &เหมือนauto &&แต่ให้การเข้าถึงแบบอ่านอย่างเดียว

สิ่งที่เกี่ยวกับประเภทดั้งเดิม / ไม่ใช่ดั้งเดิม?

ไม่มีความแตกต่างกัน

สิ่งนี้ใช้กับช่วงที่อิงกับลูปด้วยหรือไม่

ใช่. ใช้หลักการข้างต้น

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

คุณยังกล่าวถึงauto constโดยไม่มีการอ้างอิง วิธีนี้ใช้งานได้ แต่ไม่ได้ใช้บ่อยนักเนื่องจากไม่ค่อยมีข้อได้เปรียบในการเข้าถึงสิ่งที่คุณเป็นเจ้าของอยู่แล้ว


ซัตเทอร์บอกว่าระบบอัตโนมัติและแทร็กความเสถียร
Jesse Pepper

1
@JessePepper ใช่ (เป็นเรื่องแปลกเล็กน้อยที่จะดึงดูดผู้มีอำนาจ) คุณกำลังอ้างถึงส่วนหนึ่งของสิ่งนี้หรือไม่?
Potatoswatter

ในสาระauto&น่าจะเป็นทางเลือกที่ดี แต่ใช้const auto&เมื่อคุณต้องการเพิ่มความมั่นคงที่ยังไม่มี auto&&มีไว้สำหรับการส่งต่อซึ่งฉันคิดว่าเกิดขึ้นบ่อยกว่าที่ซัตเตอร์คิด ตัวอย่างเช่นคุณอาจต้องการเก็บค่าที่ส่งคืนโดยauto&&แล้ว "ส่งต่อ" ไปยังสองสิ่งเช่น std :: cout เพื่อดูค่าสำหรับการดีบักและส่งต่อไปยังฟังก์ชันอื่น ๆ ฉันเคยใช้ auto && บ่อยกว่า แต่โดนมันกัดครั้งหรือสองครั้งเมื่อมันทำสิ่งที่ไม่คาดคิด ฉันหวังว่าฉันจะสังเกตเห็นสิ่งที่ผิดพลาดมากขึ้น!
Jesse Pepper

@JessePepper ใช่auto&&เกี่ยวข้องกับคุณลักษณะภาษาที่ขาดหายไปซึ่งควรอนุญาตให้มีการแบ่งคำสั่งใด ๆ ออกเป็นข้อความย่อย ส่วนที่หายไปคือการยืดอายุการใช้งาน…ฉันใช้ความพยายามไม่น้อยในการแก้ไขปัญหานี้ แต่ไม่มีใครสังเกตเห็น อย่าใส่สต็อกมากเกินไปในนัก
วิชาการ

ใน auto const: การเขียน auto const x = fn () อาจจะเป็นธรรมชาติมากกว่า หากคุณทราบว่าฟังก์ชันไม่ส่งคืนข้อมูลอ้างอิงและคุณต้องการให้อ็อบเจ็กต์ x ไม่เปลี่ยนแปลงเพื่อหลีกเลี่ยงจุดบกพร่องหรือเอกสารที่ใช้ในขอบเขต ในทำนองเดียวกันคุณจะไม่เขียนตามปกติ: const int & x = 1; แต่ const อัตโนมัติ & จะให้ผลลัพธ์ที่เท่าเทียมกันเนื่องจากกฎการขยายอายุการใช้งานสำหรับการอ้างอิงที่ประกาศในลักษณะนี้
Spacen Jasset

47

ใช่มันถูกต้องในการใช้autoและauto&สำหรับตัวแปรท้องถิ่น auto&เมื่อได้รับผลตอบแทนประเภทของฟังก์ชั่นก็ยังเป็นที่ถูกต้องที่จะใช้ สิ่งนี้ใช้สำหรับช่วงที่อิงกับลูปเช่นกัน

กฎทั่วไปสำหรับการใช้งานautoคือ:

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

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการระบุอัตโนมัติที่นี่


10

autoใช้กลไกเดียวกับการหักประเภทเป็นเทมเพลตข้อยกเว้นเดียวที่ฉันทราบว่าเป็นของรายการวงเล็บปีกกาซึ่งอนุมานโดยautoเป็นstd::initializer_listแต่ไม่อนุมานในบริบทเทมเพลต

auto x = expression;

ทำงานโดยการลอกการอ้างอิงและคุณสมบัติ CV ทั้งหมดออกจากประเภทของนิพจน์ด้านขวามือก่อนจากนั้นจึงจับคู่ประเภท ตัวอย่างเช่นถ้าคุณมีconst int& f(){...}แล้วauto x = f();ฉงนฉงายxเป็นintและไม่ได้ const int&

รูปแบบอื่น ๆ

auto& x = expression

ไม่ได้ตัด CV-บ่นดังนั้นโดยใช้ตัวอย่างข้างต้นauto& x = f()ฉงนฉงายเป็นx const int&ชุดค่าผสมอื่น ๆ เพียงแค่เพิ่มคุณสมบัติ CV

หากคุณต้องการให้ประเภทของคุณถูกอนุมานด้วยคุณสมบัติอ้างอิง cv-ref เสมอให้ใช้คำที่น่าอับอายdecltype(auto)ใน C ++ 14 ซึ่งใช้decltypeกฎการหักประเภท

ดังนั้นในสั้นถ้าคุณต้องการสำเนาใช้ถ้าคุณต้องการที่อ้างอิงการใช้งานauto auto&ใช้constเมื่อใดก็ตามที่คุณต้องการเพิ่มเติมconst-ness


แก้ไข มีกรณีการใช้งานเพิ่มเติม

auto&& x = expression;

ซึ่งใช้กฎการยุบการอ้างอิงเช่นเดียวกับในกรณีของการส่งต่อการอ้างอิงในโค้ดเทมเพลต ถ้าexpressionเป็น lvalue แล้วxคือการอ้างอิง lvalue กับ expressionCV-บ่นของ ถ้าexpressionเป็นค่า rvalue xจะเป็นการอ้างอิง rvalue


@ Potatoswatter ขอบคุณแก้ไข ฉันสงสัยเกี่ยวกับพันธุ์สำหรับrvalues. มีวิธีทดสอบง่ายๆหรือไม่? และคุณจะมี rvalue ที่ผ่านการรับรอง CV ได้อย่างไร? ในฟังก์ชัน return cv จะถูกละทิ้ง
vsoftco

ไม่มันจะไม่ถูกทิ้งเมื่อส่งคืนฟังก์ชัน ซึ่งจะถูกละทิ้งสำหรับค่า pr ของประเภทสเกลาร์ทั้งหมด (C ++ 14 [และรุ่นอื่น ๆ ] §5 / 6) คุณสามารถรับได้โดยใช้การเรียกใช้ฟังก์ชันหรือการส่งสัญกรณ์ ค่า xvalues ​​ที่ผ่านการรับรอง Cv จะทำงานเหมือนกับสิ่งอื่น ๆ : auto && x = std::move< const int >( 5 );จะประกาศint const && xแม้ว่าจะไม่ค่อยได้ใช้
Potatoswatter

@ Potatoswatter ขอบคุณคุณพูดถูกความผิดพลาดของฉัน ฉันทดสอบครั้งแรกกับ POD ซึ่งในกรณีนี้ CV จะถูกทิ้งและคิดว่าเป็นกรณีทั่วไป แน่นอนว่าไม่ควรทิ้งเนื่องจากโดยทั่วไปอาจต้องการรักษา cv ไว้ (เช่นไม่สามารถเรียกใช้ฟังก์ชัน non-const member ในผลตอบแทน rvalue)
vsoftco

ทิ้งสำหรับประเภทสเกลาร์ POD อาจเป็นคลาส อย่างไรก็ตามมันเป็นมุมแฮ็กของจุดตัดของโมเดลนิพจน์และโมเดลอ็อบเจ็กต์
Potatoswatter

2

เมื่อสร้างตัวแปรภายในการใช้ (const) auto & หรือ auto ถูกต้องหรือไม่

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

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

ถูกกฎหมาย? ใช่กับ const ปฏิบัติที่ดีที่สุด? อาจจะไม่ไม่ อย่างน้อยไม่ใช่กับ C ++ 11 โดยเฉพาะอย่างยิ่งไม่ถ้าค่าที่ส่งคืนจาก SomeMethod () เป็นค่าชั่วคราวอยู่แล้ว คุณจะต้องการเรียนรู้เกี่ยวกับ C ++ 11 move semantics, copy elision และ return optimization: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- มูลค่า /

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

สิ่งที่เกี่ยวกับประเภทดั้งเดิม? ฉันถือว่า const auto sum = 1 + 2; ถูกต้อง.

ใช่นี่เป็นเรื่องปกติ

สิ่งนี้ใช้กับช่วงที่อิงกับลูปด้วยหรือไม่

สำหรับ (const auto & object: objects)

ใช่นี่ก็ดีเช่นกัน ฉันเขียนโค้ดประเภทนี้ในที่ทำงานตลอดเวลา

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