มีประโยชน์ในการผ่านโดยตัวชี้ไปผ่านโดยอ้างอิงใน C ++?


225

ประโยชน์ของการผ่านโดยตัวชี้ผ่านการอ้างอิงใน C ++ คืออะไร

เมื่อเร็ว ๆ นี้ฉันได้เห็นตัวอย่างจำนวนมากที่เลือกการส่งผ่านอาร์กิวเมนต์ของพอยน์เตอร์แทนที่จะส่งผ่านการอ้างอิง มีประโยชน์ในการทำเช่นนี้?

ตัวอย่าง:

func(SPRITE *x);

ด้วยการโทร

func(&mySprite);

เมื่อเทียบกับ

func(SPRITE &x);

ด้วยการโทร

func(mySprite);

อย่าลืมเกี่ยวกับnewการสร้างตัวชี้และปัญหาที่เกิดจากการเป็นเจ้าของ
Martin York

คำตอบ:


216

ตัวชี้สามารถรับพารามิเตอร์ NULL พารามิเตอร์อ้างอิงไม่สามารถ หากมีโอกาสที่คุณจะต้องการผ่าน "ไม่มีวัตถุ" ให้ใช้ตัวชี้แทนการอ้างอิง

นอกจากนี้การส่งต่อโดยตัวชี้ช่วยให้คุณสามารถดูไซต์การโทรอย่างชัดเจนว่าวัตถุนั้นถูกส่งผ่านตามค่าหรือโดยการอ้างอิง:

// Is mySprite passed by value or by reference?  You can't tell 
// without looking at the definition of func()
func(mySprite);

// func2 passes "by pointer" - no need to look up function definition
func2(&mySprite);

18
คำตอบที่ไม่สมบูรณ์ การใช้พอยน์เตอร์จะไม่อนุญาตการใช้งานของวัตถุชั่วคราว / เลื่อนระดับหรือการใช้วัตถุแหลมเป็นวัตถุแบบกองซ้อน และมันจะแนะนำว่าการโต้แย้งสามารถเป็นโมฆะเมื่อส่วนใหญ่ของเวลาที่ค่า NULL ควรจะห้าม อ่านคำตอบของ litb สำหรับคำตอบที่สมบูรณ์
paercebal

การเรียกใช้ฟังก์ชันที่สองที่ใช้ในการเพิ่มความfunc2 passes by referenceคิดเห็น ในขณะที่ฉันขอขอบคุณที่คุณหมายถึงมันผ่าน "โดยการอ้างอิง" จากมุมมองระดับสูงการใช้งานโดยการส่งตัวชี้ไปที่มุมมองระดับรหัสสิ่งนี้ทำให้เกิดความสับสนมาก (ดูstackoverflow.com/questions/13382356/ ...... )
Lightness Races ใน Orbit

ฉันแค่ไม่ซื้ออันนี้ ใช่คุณส่งผ่านตัวชี้ดังนั้นจึงต้องเป็นพารามิเตอร์ขาออก
deworde

เราไม่มีเอกสารอ้างอิงนี้ใน C ใช่หรือไม่ ฉันใช้ codeblock (mingw) เวอร์ชันล่าสุดและในการเลือกโครงการ C ยังคงผ่านการอ้างอิง (func (int & a)) หรือมีให้ใน C99 หรือ C11 เป็นต้นไป?
Jon Wheelock

1
@JonWheelock: ไม่ C ไม่มีการอ้างอิงแบบผ่านเลย func(int& a)ไม่ถูกต้อง C ในเวอร์ชันมาตรฐานใด ๆ คุณอาจรวบรวมไฟล์ของคุณเป็น C ++ โดยไม่ได้ตั้งใจ
Adam Rosenfield

245

ผ่านตัวชี้

  • ผู้โทรต้องใช้ที่อยู่ -> ไม่โปร่งใส
  • 0 nothingค่าสามารถให้กับค่าเฉลี่ย สิ่งนี้สามารถใช้เพื่อระบุอาร์กิวเมนต์ที่เป็นทางเลือก

ผ่านการอ้างอิง

  • ผู้โทรเพิ่งผ่านวัตถุ -> โปร่งใส จะต้องใช้สำหรับการบรรทุกเกินพิกัดเนื่องจากการบรรทุกเกินพิกัดสำหรับประเภทตัวชี้เป็นไปไม่ได้ (พอยน์เตอร์เป็นประเภทบิวด์อิน) ดังนั้นคุณไม่สามารถ string s = &str1 + &str2;ใช้พอยน์เตอร์ได้
  • ไม่มีค่า 0 ที่เป็นไปได้ -> ฟังก์ชั่นที่เรียกว่าไม่จำเป็นต้องตรวจสอบ
  • อ้างอิงถึง const ยังยอมรับ temporaries void f(const T& t); ... f(T(a, b, c));:, ตัวชี้ไม่สามารถใช้เช่นนั้นเนื่องจากคุณไม่สามารถใช้ที่อยู่ของชั่วคราว
  • ท้ายสุด แต่ไม่ท้ายสุดการอ้างอิงง่ายต่อการใช้ -> โอกาสน้อยที่จะเกิดข้อบกพร่อง

7
การส่งต่อด้วยตัวชี้จะเพิ่ม 'การโอนสิทธิ์การเป็นเจ้าของหรือไม่' คำถาม. นี่ไม่ใช่กรณีที่มีการอ้างอิง
Frerich Raabe

43
ฉันไม่เห็นด้วยกับ "โอกาสที่จะเกิดข้อบกพร่องน้อยลง" เมื่อตรวจสอบไซต์การโทรและผู้อ่านเห็น "foo (& s)" เป็นที่ชัดเจนทันทีว่าอาจมีการแก้ไข เมื่อคุณอ่าน "foo (s)" มันจะไม่ชัดเจนถ้า s อาจถูกแก้ไข นี่คือแหล่งสำคัญของข้อบกพร่อง บางทีโอกาสในการเกิดข้อผิดพลาดบางประเภทมีน้อยกว่า แต่โดยรวมแล้วการอ้างอิงโดยผ่านเป็นแหล่งของข้อบกพร่องขนาดใหญ่
William Pursell

25
"โปร่งใส" คุณหมายถึงอะไร
Gbert90

2
@ Gbert90 ถ้าคุณเห็น foo (& a) ที่ไซต์การโทรคุณรู้ว่า foo () ใช้ตัวชี้ประเภท หากคุณเห็น foo (a) คุณไม่รู้ว่าใช้การอ้างอิงหรือไม่
Michael J. Davenport

3
@ MichaelJ.Davenport - ในคำอธิบายของคุณคุณแนะนำ "โปร่งใส" เพื่อหมายถึงบางสิ่งบางอย่างตามแนว "เห็นได้ชัดว่าผู้โทรกำลังส่งตัวชี้ แต่ไม่ชัดเจนว่าผู้โทรกำลังส่งการอ้างอิง" ในโพสต์ของโยฮันเนสเขาบอกว่า "การส่งต่อโดยตัวชี้ - ผู้โทรต้องใช้ที่อยู่ -> ไม่โปร่งใส" และ "ผ่านการอ้างอิง - ผู้โทรเพิ่งผ่านวัตถุ -> โปร่งใส" - ซึ่งเกือบตรงกันข้ามกับสิ่งที่คุณพูด . ฉันคิดว่าคำถามของ Gbert90 "คุณหมายถึงอะไรโดย" โปร่งใส "" ยังคงใช้ได้
Happy Green Kid Naps

66

ฉันชอบการให้เหตุผลโดยบทความจาก "cplusplus.com:"

  1. ผ่านค่าเมื่อฟังก์ชั่นไม่ต้องการแก้ไขพารามิเตอร์และค่านั้นง่ายต่อการคัดลอก (ints, doubles, char, bool, etc ... ประเภทที่เรียบง่าย std :: string, std :: vector, และ STL อื่น ๆ ทั้งหมด ภาชนะบรรจุไม่ใช่ประเภทที่ง่าย)

  2. ผ่านตัวชี้ const เมื่อค่าใช้จ่ายสูงในการคัดลอกและฟังก์ชันไม่ต้องการแก้ไขค่าที่ชี้ไปที่ AND NULL เป็นค่าที่ถูกต้องและคาดหวังว่าฟังก์ชันนั้นจะจัดการ

  3. ส่งผ่านตัวชี้ที่ไม่ใช่ const เมื่อค่ามีราคาแพงในการคัดลอกและฟังก์ชันต้องการแก้ไขค่าที่ชี้ไปที่ AND NULL เป็นค่าที่ถูกต้องและคาดหวังว่าฟังก์ชันนั้นจะจัดการ

  4. ผ่านการอ้างอิง const เมื่อค่าใช้จ่ายสูงในการคัดลอกและฟังก์ชันไม่ต้องการแก้ไขค่าที่อ้างถึง AND NULL จะไม่เป็นค่าที่ถูกต้องหากใช้ตัวชี้แทน

  5. ผ่านการอ้างอิงแบบไม่ต่อเนื่องเมื่อค่ามีราคาแพงในการคัดลอกและฟังก์ชันต้องการแก้ไขค่าที่อ้างถึง AND NULL จะไม่เป็นค่าที่ถูกต้องหากใช้ตัวชี้แทน

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

http://www.cplusplus.com/articles/z6vU7k9E/

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

ไม่ว่าจะเป็นค่าอินพุตเอาต์พุตเอาต์พุตที่แก้ไขได้ ฯลฯ ควรอยู่ในเอกสาร / ข้อคิดเห็นเกี่ยวกับฟังก์ชันหลังจากทั้งหมด


ใช่สำหรับฉันคำที่เกี่ยวข้องกับค่า NULL เป็นข้อกังวลหลักที่นี่ ขอบคุณสำหรับการอ้างอิง ..
binaryguy

62

อัลเลนโฮล์บ "พอเชือกเพื่อยิงตัวเองในเท้า" แสดงกฎ 2 ข้อต่อไปนี้:

120. Reference arguments should always be `const`
121. Never use references as outputs, use pointers

เขาแสดงเหตุผลหลายประการที่เพิ่มการอ้างอิงไปยัง C ++:

  • พวกเขาจำเป็นต้องกำหนดตัวสร้างสำเนา
  • จำเป็นสำหรับโอเปอเรเตอร์โอเวอร์โหลด
  • const การอ้างอิงช่วยให้คุณมีความหมายแบบ pass-by-value ขณะที่หลีกเลี่ยงการคัดลอก

ประเด็นหลักของเขาคือการอ้างอิงไม่ควรใช้เป็นพารามิเตอร์ 'เอาท์พุท' เพราะที่ไซต์การโทรไม่มีข้อบ่งชี้ว่าพารามิเตอร์นั้นเป็นการอ้างอิงหรือพารามิเตอร์ค่า ดังนั้นกฎของเขาคือใช้constการอ้างอิงเป็นข้อโต้แย้งเท่านั้น

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


8
จุดยืนของฉันในอาร์กิวเมนต์นั้นคือถ้าชื่อฟังก์ชั่นทำให้ชัดเจนโดยไม่ต้องตรวจสอบเอกสารว่าพารามิเตอร์จะถูกแก้ไขแล้วการอ้างอิงที่ไม่ใช่แบบ const นั้นก็โอเค ดังนั้นโดยส่วนตัวฉันอนุญาต "getDetails (DetailStruct & result)" ตัวชี้มีการเพิ่มความเป็นไปได้ที่น่าเกลียดของอินพุต NULL
Steve Jessop

3
นี่เป็นสิ่งที่ทำให้เข้าใจผิด แม้ว่าบางคนไม่ชอบการอ้างอิงพวกเขาเป็นส่วนสำคัญของภาษาและควรใช้เป็นอย่างนั้น บรรทัดของการให้เหตุผลนี้ก็เหมือนกับว่าอย่าใช้แม่แบบคุณสามารถใช้คอนเทนเนอร์ของ void * เพื่อเก็บประเภทใดก็ได้ อ่านคำตอบโดย litb
David Rodríguez - dribeas

4
ฉันไม่เห็นว่าสิ่งนี้ทำให้เข้าใจผิด - มีบางครั้งที่จำเป็นต้องมีการอ้างอิงและมีหลายครั้งที่วิธีปฏิบัติที่ดีที่สุดอาจแนะนำให้ไม่ใช้พวกเขาแม้ว่าคุณจะทำได้ เดียวกันสามารถพูดได้สำหรับคุณสมบัติของภาษาใด ๆ - มรดกเพื่อนที่ไม่ได้เป็นสมาชิกผู้ประกอบการมากเกินไป, MI, ฯลฯ ...
Michael Burr

อย่างไรก็ตามฉันเห็นด้วยว่าคำตอบของ litb นั้นดีมากและแน่นอนกว่านี้มาก - ฉันเพิ่งเลือกที่จะให้ความสำคัญกับการอภิปรายเหตุผลในการหลีกเลี่ยงการใช้การอ้างอิงเป็นพารามิเตอร์เอาต์พุต
Michael Burr

1
กฎนี้ใช้ในคำแนะนำสไตล์ Google c ++: google-styleguide.googlecode.com/svn/trunk/…
Anton Daneyko

9

ชี้แจงถึงการโพสต์ก่อนหน้านี้:


การอ้างอิงไม่ใช่การรับประกันในการรับพอยน์เตอร์ที่ไม่ใช่นัล (แม้ว่าเรามักจะปฏิบัติต่อพวกเขาเช่นนี้)

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

bool test( int & a)
{
  return (&a) == (int *) NULL;
}

int
main()
{
  int * i = (int *)NULL;
  cout << ( test(*i) ) << endl;
};

ปัญหาที่แท้จริงที่ฉันมีกับการอ้างอิงอยู่กับโปรแกรมเมอร์คนอื่น ๆ ต่อจากนี้เรียกว่าIDIOTSที่จัดสรรใน Constructor, จัดสรรคืนใน Destructor และไม่สามารถจัดหา Constructor หรือตัวดำเนินการ = () ได้

ทันใดนั้นมีโลกของความแตกต่างระหว่างfoo (บาร์ BAR)และfoo (BAR &บาร์) (การดำเนินการคัดลอก bitwise อัตโนมัติถูกเรียกใช้การยกเลิกการจัดสรรใน destructor จะถูกเรียกสองครั้ง)

นักแปลสมัยใหม่ที่โชคดีจะรับการจัดสรรคืนสองเท่าของตัวชี้เดียวกันนี้ 15 ปีที่แล้วพวกเขาไม่ได้ (ภายใต้ gcc / g ++ ให้ใช้setenv MALLOC_CHECK_ 0เพื่อทบทวนวิธีเก่า ๆ ) ผลลัพธ์ภายใต้ DEC UNIX ในหน่วยความจำเดียวกันที่จัดสรรให้กับวัตถุสองชนิดที่แตกต่างกัน มีการดีบักความสนุกสนานมากมายที่นั่น ...


เพิ่มเติมจริง:

  • การอ้างอิงซ่อนว่าคุณกำลังเปลี่ยนแปลงข้อมูลที่เก็บไว้ที่อื่น
  • ง่ายต่อการสับสนกับการอ้างอิงกับวัตถุที่คัดลอก
  • พอยน์เตอร์ทำให้มันชัดเจน!

16
นั่นไม่ใช่ปัญหาของฟังก์ชั่นหรือการอ้างอิง คุณกำลังละเมิดกฎภาษา การยกเลิกการอ้างอิงตัวชี้โมฆะด้วยตัวเองเป็นพฤติกรรมที่ไม่ได้กำหนดไว้แล้ว "การอ้างอิงไม่ใช่การรับประกันในการรับพอยน์เตอร์ที่ไม่เป็นค่าว่าง": ตัวมาตรฐานบอกว่ามันเป็น วิธีอื่น ๆ ประกอบด้วยพฤติกรรมที่ไม่ได้กำหนด
Johannes Schaub - litb

1
ฉันเห็นด้วยกับ litb ในขณะที่เป็นจริงรหัสที่คุณแสดงให้เราเห็นก็คือการก่อวินาศกรรมมากกว่าสิ่งอื่นใด มีวิธีการก่อวินาศกรรมอะไรรวมทั้งเครื่องหมาย "อ้างอิง" และ "ตัวชี้"
paercebal

1
ฉันบอกว่ามันคือ "พาคุณออกไปข้างหลังโค้ดที่ไม่ดีในป่า"! ในหลอดเลือดดำเดียวกันคุณสามารถมี i = new FOO; ลบฉัน การทดสอบ (* i); ตัวชี้ห้อย / การอ้างอิงเกิดขึ้นอีกอันหนึ่ง
Mr.Ree

1
มันจริงไม่dereferencingโมฆะว่าเป็นปัญหา แต่ใช้ว่า dereferenced (null) วัตถุ ดังนั้นจึงไม่มีความแตกต่าง (นอกเหนือจากวากยสัมพันธ์) ระหว่างตัวชี้และการอ้างอิงจากมุมมองการใช้ภาษา เป็นผู้ใช้ที่มีความคาดหวังที่แตกต่างกัน
Mr.Ree

2
ไม่ว่าคุณจะทำอะไรกับข้อมูลอ้างอิงที่ส่งคืนขณะที่คุณพูด*iโปรแกรมของคุณมีพฤติกรรมที่ไม่ได้กำหนด ตัวอย่างเช่นคอมไพเลอร์สามารถมองเห็นรหัสนี้และถือว่า "ตกลงรหัสนี้มีพฤติกรรมที่ไม่ได้กำหนดในเส้นทางของรหัสทั้งหมดดังนั้นฟังก์ชั่นทั้งหมดนี้จะต้องไม่สามารถเข้าถึงได้" จากนั้นจะถือว่าสาขาทั้งหมดที่นำไปสู่ฟังก์ชั่นนี้ไม่ได้ถูกใช้ นี่คือการเพิ่มประสิทธิภาพที่ดำเนินการเป็นประจำ
David Stone

5

คำตอบส่วนใหญ่ที่นี่ไม่สามารถแก้ปัญหาความกำกวมโดยธรรมชาติในการมีตัวชี้แบบดิบในลายเซ็นฟังก์ชันในแง่ของการแสดงเจตนา ปัญหาดังต่อไปนี้:

  • ผู้เรียกไม่ทราบว่าตัวชี้ชี้ไปที่วัตถุเดียวหรือไปยังจุดเริ่มต้นของ "อาร์เรย์" ของวัตถุ

  • ผู้เรียกไม่ทราบว่าตัวชี้ "เป็นเจ้าของ" หน่วยความจำที่ชี้ไป IE ไม่ว่าจะเป็นฟังก์ชั่นควรเพิ่มหน่วยความจำหรือไม่ ( foo(new int)- นี่เป็นหน่วยความจำรั่วหรือไม่)

  • ผู้เรียกไม่ทราบว่าnullptrสามารถส่งผ่านไปยังฟังก์ชันได้อย่างปลอดภัยหรือไม่

ปัญหาทั้งหมดเหล่านี้ได้รับการแก้ไขโดยการอ้างอิง:

  • การอ้างอิงอ้างถึงวัตถุเดียวเสมอ

  • การอ้างอิงไม่เคยเป็นเจ้าของหน่วยความจำที่อ้างถึง แต่เป็นเพียงมุมมองในหน่วยความจำ

  • ข้อมูลอ้างอิงต้องไม่เป็นค่าว่าง

สิ่งนี้ทำให้การอ้างอิงเป็นตัวเลือกที่ดีกว่าสำหรับการใช้งานทั่วไป อย่างไรก็ตามการอ้างอิงไม่สมบูรณ์ - มีปัญหาใหญ่สองสามข้อที่ต้องพิจารณา

  • ไม่มีทางอ้อมอย่างชัดเจน นี่ไม่ใช่ปัญหากับตัวชี้แบบดิบเนื่องจากเราต้องใช้ตัว&ดำเนินการเพื่อแสดงว่าเรากำลังผ่านตัวชี้ ตัวอย่างเช่น,int a = 5; foo(a);มันไม่ชัดเจนเลยที่นี่ว่า a กำลังถูกส่งผ่านโดยการอ้างอิงและสามารถแก้ไขได้
  • Nullability จุดอ่อนของพอยน์เตอร์นี้สามารถเป็นจุดแข็งได้เมื่อเราต้องการให้การอ้างอิงของเราเป็นโมฆะ เมื่อเห็นว่าstd::optional<T&>ไม่ถูกต้อง (สำหรับเหตุผลที่ดี) พอยน์เตอร์จะบอกเราว่าคุณต้องการความถูกต้อง

ดังนั้นดูเหมือนว่าเมื่อเราต้องการการอ้างอิงที่เป็นโมฆะพร้อมกับการบอกทางอย่างชัดแจ้งเราควรไปถึง T*ใช่ไหม? ไม่ถูกต้อง!

นามธรรม

ในความสิ้นหวังของเราสำหรับความไร้ผลเราอาจถึงT*และเพียงเพิกเฉยต่อข้อบกพร่องและความกำกวมเชิงความหมายที่ระบุไว้ก่อนหน้า แต่เราควรไปถึงสิ่งที่ C ++ ทำได้ดีที่สุด: สิ่งที่เป็นนามธรรม ถ้าเราเพียงแค่เขียนคลาสที่ล้อมรอบพอยน์เตอร์เราจะได้รับการแสดงออกเช่นเดียวกับความไร้ประสิทธิภาพและความไม่แน่นอนทางอ้อม

template <typename T>
struct optional_ref {
  optional_ref() : ptr(nullptr) {}
  optional_ref(T* t) : ptr(t) {}
  optional_ref(std::nullptr_t) : ptr(nullptr) {}

  T& get() const {
    return *ptr;
  }

  explicit operator bool() const {
    return bool(ptr);
  }

private:
  T* ptr;
};

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

void foo(optional_ref<int> x) {
  if (x) {
    auto y = x.get();
    // use y here
  }
}

int x = 5;
foo(&x); // explicit indirection here
foo(nullptr); // nullability

เราบรรลุเป้าหมายของเราแล้ว! ตอนนี้ให้เราเห็นประโยชน์เมื่อเทียบกับตัวชี้ดิบ

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

เราสามารถทำให้ส่วนต่อประสานที่ซับซ้อนมากขึ้นจากที่นี่เช่นการเพิ่มตัวดำเนินการความเท่าเทียมกัน monadic get_orและmapส่วนต่อประสานซึ่งเป็นวิธีการที่ได้รับคุณค่าหรือส่งข้อยกเว้นconstexprสนับสนุน ที่สามารถทำได้โดยคุณ

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


3

ไม่ได้จริงๆ ภายในผ่านการอ้างอิงจะดำเนินการโดยผ่านที่อยู่ของวัตถุอ้างอิง ดังนั้นจึงไม่มีประสิทธิภาพใด ๆ เพิ่มขึ้นโดยการส่งตัวชี้

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


1
นั่นเป็นทั้งข้อดีและข้อเสีย API จำนวนมากใช้พอยน์เตอร์ NULL เพื่อหมายถึงสิ่งที่มีประโยชน์ (เช่น NULL timespec รอตลอดไปในขณะที่ค่านั้นจะรอนาน)
Greg Rogers

1
@ ไบรอัน: ฉันไม่ต้องการที่จะจู้จี้จุกจิก แต่: ฉันจะไม่พูดว่ามีใครรับประกันว่าจะได้รับตัวอย่างเมื่อได้รับการอ้างอิง การอ้างอิงที่เป็นอันตรายยังคงเป็นไปได้หากผู้เรียกฟังก์ชั่นยกเลิกการอ้างอิงตัวชี้ห้อยซึ่งผู้เรียกไม่สามารถทราบได้
foraidt

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

โปรแกรมที่มีการอ้างอิงห้อยอยู่นั้นไม่ถูกต้อง C ++ ดังนั้นใช่รหัสสามารถสันนิษฐานได้ว่าการอ้างอิงทั้งหมดนั้นถูกต้อง
Konrad Rudolph

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