การส่งผ่านข้อโต้แย้งเป็นการอ้างอิง const การเพิ่มประสิทธิภาพก่อนกำหนดหรือไม่


20

"การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากฐานของความชั่วร้ายทั้งหมด"

ฉันคิดว่าสิ่งนี้เราทุกคนสามารถตกลงกันได้ และฉันพยายามอย่างหนักเพื่อหลีกเลี่ยงการทำเช่นนั้น

แต่เมื่อเร็ว ๆ นี้ผมได้รับการสงสัยเกี่ยวกับการปฏิบัติของพารามิเตอร์ผ่านโดยอ้างอิง constแทนโดยราคา ฉันได้รับการสอน / เรียนรู้ว่าการโต้แย้งฟังก์ชั่นที่ไม่สำคัญ (เช่นประเภทที่ไม่ใช่แบบดั้งเดิม) ควรจะถูกส่งผ่านโดยการอ้างอิง const - หนังสือบางเล่มที่ฉันได้อ่านแนะนำว่านี่เป็น "แนวปฏิบัติที่ดีที่สุด"

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

void fooByValue(SomeDataStruct data);   

และ

void fooByReference(const SomeDataStruct& data);

เป็นวิธีปฏิบัติที่ฉันได้เรียนรู้ - ผ่านการอ้างอิง const (โดยค่าเริ่มต้นสำหรับประเภทที่ไม่สำคัญ) - การเพิ่มประสิทธิภาพก่อนวัยอันควร?


1
ดูเพิ่มเติมที่: F.call ใน C ++ Core Guidelinesสำหรับการอภิปรายกลยุทธ์การส่งผ่านพารามิเตอร์ต่างๆ
amon


1
@DocBrown คำตอบที่ได้รับการยอมรับสำหรับคำถามนั้นหมายถึงหลักการความประหลาดใจน้อยที่สุดซึ่งอาจนำไปใช้ที่นี่ด้วย (เช่นการใช้การอ้างอิง const คือมาตรฐานอุตสาหกรรม ฯลฯ ) ที่กล่าวว่าฉันไม่เห็นด้วยกับคำถามที่ซ้ำกัน: คำถามที่คุณอ้างถึงถามว่าเป็นการปฏิบัติที่ไม่ถูกต้องหรือไม่ (โดยทั่วไป) พึ่งพาการปรับให้เหมาะสมของคอมไพเลอร์ คำถามนี้ถามผกผัน: การส่งผ่าน const อ้างอิงถึงการเพิ่มประสิทธิภาพ (ก่อนกำหนด)
CharonX

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

1
@DocBrown: ดังนั้นก่อนที่คุณจะประกาศว่ามันเป็นล่อให้ชี้ไปที่ในคำถามมันบอกว่าคอมไพเลอร์จะได้รับอนุญาตและสามารถ "เพิ่มประสิทธิภาพ" ที่
Deduplicator

คำตอบ:


49

"การเพิ่มประสิทธิภาพก่อนวัยอันควร" ไม่ได้เกี่ยวกับการใช้ optimisations ต้น มันเกี่ยวกับการปรับให้เหมาะสมก่อนที่จะเข้าใจปัญหาก่อนที่จะเข้าใจรันไทม์และมักจะทำให้โค้ดอ่านน้อยลงและสามารถบำรุงรักษาได้น้อยกว่าสำหรับผลลัพธ์ที่น่าสงสัย

การใช้ "const &" แทนการส่งต่อวัตถุตามค่าเป็นวิธีการเพิ่มประสิทธิภาพที่เข้าใจกันดีโดยมีผลกระทบที่เข้าใจกันดีเกี่ยวกับรันไทม์โดยไม่ต้องใช้ความพยายามและไม่มีผลเสียใด ๆ ต่อความสามารถในการอ่านและการบำรุงรักษา มันช่วยปรับปรุงทั้งสองอย่างเพราะมันบอกฉันว่าการโทรจะไม่แก้ไขวัตถุที่ส่งผ่านดังนั้นการเพิ่ม "const &" ทันทีเมื่อคุณเขียนรหัสไม่ใช่ความสำคัญ


2
ฉันเห็นด้วยกับส่วนของคำตอบของคุณ แต่การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นสิ่งแรกและสำคัญที่สุดเกี่ยวกับการปรับให้เหมาะสมก่อนที่จะส่งผลกระทบต่อประสิทธิภาพที่สังเกตเห็นได้ และฉันไม่คิดว่าโปรแกรมเมอร์ C ++ ส่วนใหญ่ (ซึ่งรวมถึงตัวเอง) ทำการวัดใด ๆ ก่อนที่จะใช้const&ดังนั้นฉันคิดว่าคำถามนี้ค่อนข้างสมเหตุสมผล
Doc Brown

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

3
ฉันไม่ใช่ผู้เชี่ยวชาญ C ดังนั้นคำถาม: const& fooบอกว่าฟังก์ชั่นจะไม่แก้ไข foo ดังนั้นผู้โทรจึงปลอดภัย แต่ค่าคัดลอกบอกว่าไม่มีหัวข้ออื่น ๆสามารถเปลี่ยน foo ดังนั้นcalleeมีความปลอดภัย ขวา? ดังนั้นในแอพมัลติเธรดคำตอบขึ้นอยู่กับความถูกต้องไม่ใช่การปรับให้เหมาะสม
949300

1
@DocBrown คุณอาจถามแรงจูงใจของนักพัฒนาที่ใส่กลุ่ม &? หากเขาทำเพื่อการแสดงเท่านั้นโดยไม่คำนึงถึงส่วนที่เหลือมันอาจถูกพิจารณาว่าเป็นการเพิ่มประสิทธิภาพก่อนวัยอันควร ตอนนี้ถ้าเขาวางไว้เพราะเขารู้ว่ามันจะเป็นพารามิเตอร์ const แล้วเขาเพียงบันทึกรหัสของเขาเองและเปิดโอกาสให้คอมไพเลอร์เพิ่มประสิทธิภาพซึ่งดีกว่า
Walfrat

1
@ user949300: ฟังก์ชั่นไม่กี่อนุญาตให้มีการแก้ไขข้อโต้แย้งของพวกเขาพร้อมกันหรือโดยการเรียกกลับที่ใช้และพวกเขาพูดอย่างนั้น
Deduplicator

16

TL; DR: การอ้างอิงผ่าน const ยังคงเป็นความคิดที่ดีใน C ++ ทุกสิ่งที่ถูกพิจารณา ไม่ใช่การเพิ่มประสิทธิภาพก่อนวัยอันควร

TL; DR2: ภาษิตส่วนใหญ่ไม่สมเหตุสมผลจนกว่าจะเป็นเช่นนั้น


จุดมุ่งหมาย

คำตอบนี้จะพยายามขยายรายการที่เชื่อมโยงในแนวทางหลักของC ++ (กล่าวถึงครั้งแรกในความคิดเห็นของ amon) เล็กน้อย

คำตอบนี้ไม่ได้พยายามที่จะแก้ไขปัญหาของวิธีการคิดและนำไปใช้อย่างถูกต้อง adages ต่าง ๆ ที่แพร่กระจายอย่างกว้างขวางในวงการโปรแกรมเมอร์โดยเฉพาะอย่างยิ่งปัญหาของการกระทบยอดระหว่างข้อสรุปหรือหลักฐานที่ขัดแย้งกัน


การบังคับใช้

คำตอบนี้ใช้กับการเรียกใช้ฟังก์ชัน (ขอบเขตซ้อนกันที่ไม่สามารถถอดออกได้ในเธรดเดียวกัน) เท่านั้น

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


เมื่อใดที่จะผ่านค่า

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

สำหรับสถานการณ์ที่ผู้ใช้ต้องการการโคลนวัตถุหรือการรวมให้ส่งค่าตามค่าซึ่งสำเนาของผู้ปฏิบัติงานนั้นจะตอบสนองความต้องการของวัตถุที่ถูกโคลน


เมื่อใดที่จะผ่านการอ้างอิง ฯลฯ

สำหรับสถานการณ์อื่น ๆ ผ่านตัวชี้การอ้างอิงตัวชี้สมาร์ทจับ (ดู: สำนวนจับร่างกาย) ฯลฯ เมื่อใดก็ตามที่มีการปฏิบัติตามคำแนะนำนี้ให้ใช้หลักการของความถูกต้อง const ตามปกติ

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


กระบวนทัศน์ที่ผิดปกติ

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


ข้อกำหนดทางภาษามีผลต่อคำตอบนี้อย่างไรก่อนพิจารณาการปรับให้เหมาะสม

Sub-TL; DR การขยายการอ้างอิงไม่ควรเรียกใช้โค้ด ผ่าน const-reference เป็นไปตามเกณฑ์นี้ อย่างไรก็ตามภาษาอื่น ๆ ทั้งหมดสนองเกณฑ์นี้ได้อย่างง่ายดาย

(โปรแกรมเมอร์มือใหม่ C ++ ขอแนะนำให้ข้ามส่วนนี้ไปโดยสิ้นเชิง)

(จุดเริ่มต้นของส่วนนี้ได้รับแรงบันดาลใจส่วนหนึ่งจากคำตอบของ gnasher729 อย่างไรก็ตามถึงข้อสรุปที่แตกต่างกัน)

C ++ อนุญาตให้ผู้สร้างสำเนาที่ผู้ใช้กำหนดและผู้ดำเนินการที่ได้รับมอบหมาย

(นี่คือ (เคย)) เป็นตัวเลือกที่กล้าหาญที่น่าประทับใจและน่าเสียดายมันแตกต่างจากบรรทัดฐานที่ยอมรับได้ในปัจจุบันในการออกแบบภาษา)

แม้ว่า c ++ Programmer ไม่ได้กำหนดหนึ่ง c ++ memcpyคอมไพเลอร์จะต้องสร้างวิธีการดังกล่าวตามหลักการใช้ภาษาและจากนั้นตรวจสอบว่าความต้องการรหัสเพิ่มเติมที่จะดำเนินการอื่นที่ไม่ใช่ ตัวอย่างเช่นclass/ structที่มีstd::vectorสมาชิกจะต้องมีตัวคัดลอกคอนสตรัคเตอร์และผู้ประกอบการที่ได้รับมอบหมายที่ไม่สำคัญ

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

เมื่อมีการส่งการอ้างอิงหรือตัวชี้ (รวมถึงการอ้างอิง const) ใน C ++ (หรือ C) โปรแกรมเมอร์จะมั่นใจได้ว่าจะไม่มีการเรียกใช้โค้ดพิเศษ (ฟังก์ชั่นที่ผู้ใช้กำหนดหรือสร้างโดยคอมไพเลอร์) ยกเว้นการเผยแพร่ค่าที่อยู่ (การอ้างอิงหรือตัวชี้) นี่คือความชัดเจนของพฤติกรรมที่โปรแกรมเมอร์ C ++ รู้สึกสบายใจ

อย่างไรก็ตามฉากหลังคือภาษา C ++ นั้นมีความซับซ้อนเกินความจำเป็นโดยที่ความชัดเจนของพฤติกรรมนี้เป็นเหมือนโอเอซิส

ในการเพิ่มคำอวยพร (หรือดูถูก) เพิ่มเติม C ++ จะแนะนำการอ้างอิงสากล (r-values) เพื่ออำนวยความสะดวกผู้ใช้งานตัวดำเนินการย้ายที่ผู้ใช้กำหนดเอง (ตัวสร้างการเคลื่อนไหว สิ่งนี้มีประโยชน์ต่อกรณีการใช้งานที่มีความเกี่ยวข้องสูง (การเคลื่อนย้าย (การย้าย) ของวัตถุจากอินสแตนซ์หนึ่งไปอีกอันหนึ่งโดยการลดความจำเป็นในการคัดลอกและการโคลนนิ่งลึก อย่างไรก็ตามในภาษาอื่น ๆ มันเป็นเรื่องไร้เหตุผลที่จะพูดถึงการเคลื่อนย้ายวัตถุดังกล่าว


(ส่วนนอกหัวข้อ) ส่วนที่อุทิศให้กับบทความ "Want Speed? Pass by Value!" เขียนในปี 2009

บทความนั้นเขียนขึ้นในปี 2009 และอธิบายถึงเหตุผลในการออกแบบสำหรับ r-value ใน C ++ บทความนั้นนำเสนอการโต้แย้งที่ถูกต้องถึงข้อสรุปของฉันในส่วนก่อนหน้า อย่างไรก็ตามตัวอย่างรหัสของบทความและการเรียกร้องประสิทธิภาพได้รับการข้องแวะมานานแล้ว

Sub-TL; DRการออกแบบของซีแมนทิกส์ r-value ใน C ++ อนุญาตให้มีความหมายที่น่าประหลาดใจด้านผู้ใช้บนSortฟังก์ชันตัวอย่างเช่น สง่างามนี้เป็นไปไม่ได้ที่จะจำลอง (เลียนแบบ) ในภาษาอื่น

ฟังก์ชั่นการจัดเรียงจะถูกนำไปใช้กับโครงสร้างข้อมูลทั้งหมด ดังกล่าวข้างต้นมันจะช้าถ้ามีการทำสำเนาจำนวนมากเกี่ยวข้อง ในฐานะที่เป็นการเพิ่มประสิทธิภาพ (ที่มีความเกี่ยวข้องในทางปฏิบัติ) ฟังก์ชั่นการเรียงลำดับได้รับการออกแบบให้ทำลายในภาษาอื่น ๆ นอกเหนือจาก C ++ การทำลายหมายถึงโครงสร้างข้อมูลเป้าหมายได้รับการแก้ไขเพื่อให้บรรลุเป้าหมายการเรียงลำดับ

ใน C ++ ผู้ใช้สามารถเลือกที่จะเรียกหนึ่งในสองของการใช้งาน: หนึ่งที่ทำลายล้างที่มีประสิทธิภาพที่ดีขึ้นหรือคนปกติที่ไม่ได้ปรับเปลี่ยนการป้อนข้อมูล (เทมเพลตถูกตัดออกเนื่องจากความกะทัดรัด)

/*caller specifically passes in input argument destructively*/
std::vector<T> my_sort(std::vector<T>&& input)
{
    std::vector<T> result(std::move(input)); /* destructive move */
    std::sort(result.begin(), result.end()); /* in-place sorting */
    return result; /* return-value optimization (RVO) */
}

/*caller specifically passes in read-only argument*/ 
std::vector<T> my_sort(const std::vector<T>& input)
{
    /* reuse destructive implementation by letting it work on a clone. */
    /* Several things involved; e.g. expiring temporaries as r-value */
    /* return-value optimization, etc. */
    return my_sort(std::vector<T>(input));  
}

/*caller can select which to call, by selecting r-value*/
std::vector<T> v1 = {...};
std::vector<T> v2 = my_sort(v1); /*non-destructive*/
std::vector<T> v3 = my_sort(std::move(v1)); /*v1 is gutted*/    

นอกเหนือจากการเรียงลำดับแล้วความสง่างามนี้ยังมีประโยชน์ในการใช้อัลกอริทึมการหาค่ามัธยฐานแบบทำลายล้างในอาเรย์

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


การปรับให้เหมาะสมของคอมไพเลอร์มีผลกับคำตอบนี้อย่างไร

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

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

วัตถุที่ใหญ่กว่าค่าการลงทะเบียนเครื่องอาจถูกคัดลอกโดยคำแนะนำในการโหลด / จัดเก็บหน่วยความจำอย่างชัดเจนหรือโดยการเรียกไปยังmemcpyฟังก์ชันที่น่าเชื่อถือ ในบางแพลตฟอร์มคอมไพเลอร์จะสร้างคำสั่ง SIMD เพื่อย้ายระหว่างตำแหน่งหน่วยความจำสองแห่งซึ่งแต่ละคำสั่งนั้นจะย้ายนับสิบไบต์ (16 หรือ 32)


การอภิปรายเกี่ยวกับปัญหาของการใช้คำฟุ่มเฟื่อยหรือความยุ่งเหยิงภาพ

โปรแกรมเมอร์ C ++ คุ้นเคยกับสิ่งนี้เช่นตราบใดที่โปรแกรมเมอร์ไม่ได้เกลียด C ++ ค่าใช้จ่ายในการเขียนหรืออ่านค่าอ้างอิง const ในซอร์สโค้ดนั้นไม่น่ากลัว

การวิเคราะห์ต้นทุน - ผลประโยชน์อาจทำได้หลายครั้งก่อนหน้านี้ ฉันไม่รู้ว่ามีวิทยาศาสตร์อะไรที่ควรอ้างถึง ฉันเดาว่าการวิเคราะห์ส่วนใหญ่จะไม่ใช่ทางวิทยาศาสตร์หรือไม่สามารถทำซ้ำได้

นี่คือสิ่งที่ฉันจินตนาการ (โดยไม่มีการพิสูจน์หรือการอ้างอิงที่น่าเชื่อถือ) ...

  • ใช่มันมีผลต่อประสิทธิภาพของซอฟต์แวร์ที่เขียนด้วยภาษานี้
  • หากคอมไพเลอร์สามารถเข้าใจวัตถุประสงค์ของรหัสมันอาจเป็นไปได้ที่จะฉลาดพอที่จะทำให้มันเป็นไปโดยอัตโนมัติ
  • น่าเสียดายที่ในภาษาที่สนับสนุนความไม่แน่นอน (ตรงข้ามกับความบริสุทธิ์ในการใช้งาน) คอมไพเลอร์จะจัดประเภทสิ่งต่าง ๆ ส่วนใหญ่ว่าเป็นการกลายพันธุ์ดังนั้นการหักห้ามใจโดยอัตโนมัติของการปฏิเสธจะปฏิเสธสิ่งต่าง ๆ มากที่สุด
  • ค่าใช้จ่ายทางจิตขึ้นอยู่กับคน ผู้ที่พบว่าสิ่งนี้เป็นค่าใช้จ่ายทางจิตสูงจะปฏิเสธ C ++ เป็นภาษาโปรแกรมที่ทำงานได้

นี่เป็นหนึ่งในสถานการณ์ที่ฉันต้องการฉันสามารถตอบได้สองคำตอบแทนที่จะต้องเลือกเพียงคำเดียว ... ถอนหายใจ
CharonX

8

ในเอกสารของ DonaldKnuth "StructuredProgrammingWithGoToStatements" เขาเขียนว่า: "โปรแกรมเมอร์เสียเวลาจำนวนมากที่คิดหรือกังวลเกี่ยวกับความเร็วของส่วนที่ไม่สำคัญของโปรแกรมและความพยายามเหล่านี้อย่างมีประสิทธิภาพมีผลกระทบเชิงลบอย่างมากเมื่อพิจารณาการดีบักและบำรุงรักษา เราควรลืมประสิทธิภาพเล็กน้อยพูดถึง 97% ของเวลา: การปรับให้เหมาะสมก่อนกำหนดเป็นรากฐานของความชั่วร้ายทั้งหมด แต่เราไม่ควรพลาดโอกาสที่สำคัญ 3% " - การเพิ่มประสิทธิภาพก่อนวัยอันควร

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


3
"ถ้าคุณต้องเลือกเพียงอันเดียวให้เลือกความชัดเจน" ประการที่สองควรจะต้องการแทนในขณะที่คุณอาจจะมีการบังคับให้เลือกอื่น ๆ
Deduplicator

@Dupuplicator ขอบคุณ อย่างไรก็ตามในบริบทของ OP โปรแกรมเมอร์มีอิสระในการเลือก
Lawrence

คำตอบของคุณอ่านทั่วไปมากกว่าเล็กน้อยว่า ...
Deduplicator

@Dupuplicator Ah แต่บริบทของคำตอบของฉันคือ (เช่น) ที่โปรแกรมเมอร์เลือก หากตัวเลือกถูกบังคับให้โปรแกรมเมอร์มันจะไม่เป็น "คุณ" ที่จะเลือก :) ฉันพิจารณาการเปลี่ยนแปลงที่คุณแนะนำและจะไม่คัดค้านการแก้ไขคำตอบของฉัน แต่ฉันชอบข้อความที่มีอยู่เพื่อความชัดเจน
Lawrence

7

การส่งผ่านโดยการอ้างอิง มันไม่เกี่ยวอะไรกับประสิทธิภาพ

กฎของหัวแม่มือของริชชี่:

void foo(X x);          // I intend to own the x you gave me, whether by copy, move or direct initialisation on the call stack.     

void foo(X&& x);        // I intend to steal x from you. Do not use it other than to re-assign to it after calling me.

void foo(X const& x);   // I guarantee not to change your x

void foo(X& x);         // I may modify your x and I will leave it in a defined state

3

ในทางทฤษฎีคำตอบควรเป็นใช่ และในความเป็นจริงมันก็ใช่บางครั้ง - ตามความเป็นจริงการอ้างอิงโดย const แทนการเพิ่งผ่านค่าอาจเป็นการมองโลกในแง่ร้ายแม้ในกรณีที่ค่าส่งผ่านมีขนาดใหญ่เกินไป ลงทะเบียน (หรือส่วนใหญ่ของคนอื่น ๆ ฮิวริสติกพยายามที่จะใช้เพื่อกำหนดว่าเมื่อใดที่จะผ่านค่าหรือไม่) หลายปีที่ผ่านมา David Abrahams เขียนบทความชื่อ "Want Speed? Pass by Value!" ครอบคลุมบางกรณี ไม่ใช่เรื่องง่ายที่จะหาได้อีกต่อไป แต่ถ้าคุณสามารถขุดสำเนามันคุ้มค่าที่จะอ่าน (IMO)

ในกรณีเฉพาะของการอ้างอิงโดย const อย่างไรก็ตามฉันจะบอกว่าสำนวนนั้นเป็นที่ยอมรับกันดีว่าสถานการณ์นั้นกลับกันมากขึ้นหรือน้อยลง: เว้นแต่คุณจะรู้ว่าประเภทจะเป็นchar/ short/ int/ longคนคาดว่าจะเห็นมันผ่าน const การอ้างอิงโดยค่าเริ่มต้นดังนั้นจึงเป็นการดีที่สุดที่จะไปพร้อมกับสิ่งนั้นเว้นแต่ว่าคุณมีเหตุผลที่เฉพาะเจาะจงพอสมควร

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