มีการใช้งานตัวชี้อัจฉริยะ C ++ อะไรบ้าง?


121

การเปรียบเทียบข้อดีข้อเสียและเมื่อใดควรใช้?

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

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

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

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


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

3
มีทุกประเภทของตัวชี้สมาร์ทอื่น ๆ เช่นมีATL ชี้สมาร์ทหรือOpenSceneGraph ของ osg::ref_ptr
James McNellis

11
มีคำถามที่นี่หรือไม่?
Cody Gray

6
std::auto_ptrผมคิดว่าคุณได้เข้าใจผิด เป็นรายละเอียดการออกแบบของstd::auto_ptr_ref ไม่มีส่วนเกี่ยวข้องกับการเก็บขยะจุดประสงค์หลักคือการอนุญาตให้มีการโอนความเป็นเจ้าของอย่างปลอดภัยโดยเฉพาะอย่างยิ่งในสถานการณ์การเรียกใช้ฟังก์ชันและการส่งคืนฟังก์ชัน สามารถแก้ปัญหา "ปัญหา" ที่คุณอ้างถึงด้วยคอนเทนเนอร์มาตรฐานเท่านั้นเนื่องจาก C ++ ได้เปลี่ยนไปเพื่อให้มีการเปลี่ยนแปลงความแตกต่างระหว่างการย้ายและสำเนาและคอนเทนเนอร์มาตรฐานเพื่อใช้ประโยชน์จากสิ่งนี้ std::auto_ptrstd::auto_ptrstd::unique_ptr
CB Bailey

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

คำตอบ:


231

C ++ 03

std::auto_ptr- อาจเป็นหนึ่งในต้นฉบับที่ได้รับความทุกข์ทรมานจากโรคร่างแรกเท่านั้นที่มีสถานที่เก็บขยะที่ จำกัด ข้อเสียประการแรกคือการเรียกร้องdeleteให้ทำลายทำให้ไม่สามารถยอมรับได้ในการถืออาร์เรย์วัตถุที่จัดสรรไว้ ( new[]) เป็นเจ้าของตัวชี้ดังนั้นตัวชี้อัตโนมัติสองตัวไม่ควรมีวัตถุเดียวกัน การมอบหมายจะโอนความเป็นเจ้าของและรีเซ็ตตัวชี้อัตโนมัติrvalueเป็นตัวชี้ค่าว่าง ซึ่งอาจนำไปสู่ข้อเสียเปรียบที่เลวร้ายที่สุด ไม่สามารถใช้ภายในคอนเทนเนอร์ STL ได้เนื่องจากไม่สามารถคัดลอกข้างต้นได้ ขั้นสุดท้ายสำหรับกรณีการใช้งานคือพวกเขามีกำหนดที่จะเลิกใช้งานในมาตรฐานถัดไปของ C ++

std::auto_ptr_ref- นี่ไม่ใช่ตัวชี้อัจฉริยะ แต่เป็นรายละเอียดการออกแบบที่ใช้ร่วมกับstd::auto_ptrเพื่ออนุญาตให้คัดลอกและมอบหมายในบางสถานการณ์ โดยเฉพาะอย่างยิ่งมันสามารถใช้เพื่อแปลง non-const std::auto_ptrเป็นlvalueโดยใช้เคล็ดลับ Colvin-Gibbons หรือที่เรียกว่าตัวสร้างการย้ายเพื่อโอนความเป็นเจ้าของ

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


C ++ 11

std::unique_ptr- นี่คือเพื่อนของเราที่จะเข้ามาแทนที่std::auto_ptrซึ่งจะค่อนข้างคล้ายกันยกเว้นการปรับปรุงที่สำคัญเพื่อแก้ไขจุดอ่อนของstd::auto_ptrการทำงานกับอาร์เรย์การป้องกันค่าlvalueผ่านตัวสร้างสำเนาส่วนตัวสามารถใช้งานได้กับคอนเทนเนอร์ STL และอัลกอริทึมเป็นต้นเนื่องจากประสิทธิภาพเหนือศีรษะ และหน่วยความจำมี จำกัด นี่เป็นตัวเลือกที่เหมาะสำหรับการแทนที่หรืออาจอธิบายได้อย่างเหมาะสมกว่าว่าเป็นเจ้าของตัวชี้ดิบ ในฐานะที่เป็น "พิเศษ" std::auto_ptrหมายถึงมีเพียงหนึ่งเจ้าของตัวชี้เช่นเดียวกับก่อนหน้านี้

std::shared_ptr- ฉันเชื่อว่านี่เป็นไปตาม TR1 และได้boost::shared_ptrรับการปรับปรุงให้รวมการใช้นามแฝงและเลขคณิตของตัวชี้ด้วย ในระยะสั้นมันจะรวมการอ้างอิงตัวชี้อัจฉริยะที่นับรอบวัตถุที่จัดสรรแบบไดนามิก เนื่องจาก "ใช้ร่วมกัน" หมายความว่าตัวชี้สามารถเป็นเจ้าของได้โดยตัวชี้ที่ใช้ร่วมกันมากกว่าหนึ่งตัวเมื่อการอ้างอิงสุดท้ายของตัวชี้ที่ใช้ร่วมกันล่าสุดอยู่นอกขอบเขตวัตถุจะถูกลบอย่างเหมาะสม สิ่งเหล่านี้ยังปลอดภัยต่อเธรดและสามารถรองรับประเภทที่ไม่สมบูรณ์ได้ในกรณีส่วนใหญ่ std::make_sharedสามารถใช้เพื่อสร้างการstd::shared_ptrจัดสรรฮีปอย่างมีประสิทธิภาพโดยใช้ตัวจัดสรรเริ่มต้น

std::weak_ptr- ในทำนองเดียวกันตาม TR1 และboost::weak_ptr. นี่คือการอ้างอิงถึงวัตถุที่เป็นเจ้าของstd::shared_ptrและดังนั้นจะไม่ป้องกันการลบวัตถุหากstd::shared_ptrจำนวนการอ้างอิงลดลงเหลือศูนย์ ในการเข้าถึงตัวชี้ดิบก่อนอื่นคุณจะต้องเข้าถึงstd::shared_ptrโดยการโทรlockซึ่งจะส่งคืนค่าว่างstd::shared_ptrหากตัวชี้ที่เป็นเจ้าของหมดอายุและถูกทำลายไปแล้ว สิ่งนี้มีประโยชน์เป็นหลักในการหลีกเลี่ยงการนับการอ้างอิงที่แขวนไม่แน่นอนเมื่อใช้ตัวชี้อัจฉริยะหลายตัว


การส่งเสริม

boost::shared_ptr- อาจเป็นวิธีที่ง่ายที่สุดที่จะใช้ในสถานการณ์ที่แตกต่างกันมากที่สุด (STL, PIMPL, RAII ฯลฯ ) ซึ่งเป็นตัวชี้อัจฉริยะที่มีการอ้างอิงที่ใช้ร่วมกัน ฉันได้ยินคำบ่นเล็กน้อยเกี่ยวกับประสิทธิภาพและค่าใช้จ่ายในบางสถานการณ์ แต่ฉันคงต้องเพิกเฉยต่อพวกเขาเพราะฉันจำไม่ได้ว่าข้อโต้แย้งคืออะไร เห็นได้ชัดว่ามันเป็นที่นิยมมากพอที่จะกลายเป็นวัตถุ C ++ มาตรฐานที่รอดำเนินการและไม่มีข้อบกพร่องเกี่ยวกับบรรทัดฐานเกี่ยวกับตัวชี้อัจฉริยะที่อยู่ในใจ

boost::weak_ptr- เช่นเดียวกับคำอธิบายก่อนหน้านี้std::weak_ptrตามการใช้งานนี้อนุญาตให้ใช้การอ้างอิงที่ไม่ใช่ของเจ้าของไปยังไฟล์boost::shared_ptr. คุณไม่ต้องแปลกใจที่lock()จะเรียกใช้ตัวชี้ที่ใช้ร่วมกัน "ที่แข็งแกร่ง" และต้องตรวจสอบให้แน่ใจว่าถูกต้องเนื่องจากอาจถูกทำลายไปแล้ว อย่าลืมจัดเก็บตัวชี้ที่ใช้ร่วมกันที่ส่งคืนและปล่อยให้อยู่นอกขอบเขตทันทีที่คุณดำเนินการเสร็จมิฉะนั้นคุณจะกลับไปที่ปัญหาการอ้างอิงแบบวนซ้ำซึ่งการนับการอ้างอิงของคุณจะค้างและวัตถุจะไม่ถูกทำลาย

boost::scoped_ptr- นี่คือคลาสตัวชี้อัจฉริยะแบบธรรมดาที่มีค่าใช้จ่ายเพียงเล็กน้อยซึ่งอาจได้รับการออกแบบมาเพื่อเป็นทางเลือกที่มีประสิทธิภาพดีกว่าboost::shared_ptrเมื่อใช้งานได้ เทียบได้กับstd::auto_ptrโดยเฉพาะอย่างยิ่งในความจริงที่ว่าไม่สามารถใช้เป็นองค์ประกอบของคอนเทนเนอร์ STL ได้อย่างปลอดภัยหรือมีตัวชี้หลายตัวไปยังวัตถุเดียวกัน

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

boost::shared_array- นี่คือboost::shared_ptrสำหรับอาร์เรย์ โดยทั่วไปnew [], operator[]และแน่นอนdelete []จะอบใน. นี้สามารถนำมาใช้ในภาชนะ STL และเท่าที่ผมรู้ว่าไม่ทุกอย่างboost:shared_ptrไม่แม้ว่าคุณจะไม่สามารถใช้boost::weak_ptrกับสิ่งเหล่านี้ อย่างไรก็ตามคุณสามารถใช้ a boost::shared_ptr<std::vector<>>สำหรับฟังก์ชันการทำงานที่คล้ายกันและเพื่อฟื้นความสามารถในการใช้boost::weak_ptrอ้างอิงได้

boost::scoped_array- นี่คือboost::scoped_ptrสำหรับอาร์เรย์ เช่นเดียวกับboost::shared_arrayความดีงามของอาร์เรย์ที่จำเป็นทั้งหมดถูกอบไว้อันนี้ไม่สามารถคัดลอกได้จึงไม่สามารถใช้ในคอนเทนเนอร์ STL ได้ ฉันพบเกือบทุกที่ที่คุณพบว่าตัวเองต้องการใช้สิ่งนี้คุณอาจจะstd::vectorใช้ได้ ฉันไม่เคยพิจารณาว่าอันไหนเร็วกว่าหรือมีค่าโสหุ้ยน้อย แต่อาร์เรย์ที่กำหนดขอบเขตนี้ดูเหมือนจะเกี่ยวข้องน้อยกว่าเวกเตอร์ STL มาก เมื่อคุณต้องการเก็บการจัดสรรบนสแต็กให้พิจารณาboost::arrayแทน


Qt

QPointer- แนะนำใน Qt 4.0 นี่คือสมาร์ทพอยน์เตอร์ที่ "อ่อนแอ" ซึ่งใช้ได้เฉพาะกับQObjectคลาสที่ได้รับเท่านั้นซึ่งในเฟรมเวิร์ก Qt นั้นแทบจะทุกอย่างดังนั้นจึงไม่ใช่ข้อ จำกัด จริงๆ อย่างไรก็ตามมีข้อ จำกัด คือไม่มีตัวชี้ที่ "แข็งแรง" และแม้ว่าคุณจะตรวจสอบได้ว่าวัตถุที่อยู่ข้างใต้นั้นใช้ได้หรือisNull()ไม่ แต่คุณพบว่าวัตถุของคุณถูกทำลายทันทีหลังจากที่คุณผ่านการตรวจสอบนั้นโดยเฉพาะในสภาพแวดล้อมแบบมัลติเธรด Qt ผู้คนคิดว่าสิ่งนี้เลิกใช้แล้วฉันเชื่อว่า

QSharedDataPointer- นี่คือ "ความเชื่อ" ชี้สมาร์ทที่อาจเทียบเคียงได้กับboost::intrusive_ptrแม้ว่ามันจะมีบางส่วนที่สร้างขึ้นในหัวข้อความปลอดภัย แต่ก็ไม่ต้องการให้คุณรวมถึงวิธีการตรวจนับการอ้างอิง ( refและderef) ซึ่งคุณสามารถทำได้ด้วย QSharedDatasubclassing เช่นเดียวกับ Qt ส่วนใหญ่วัตถุจะถูกใช้อย่างดีที่สุดผ่านการสืบทอดที่กว้างขวางและการแบ่งคลาสย่อยทุกอย่างดูเหมือนจะเป็นการออกแบบที่ตั้งใจไว้

QExplicitlySharedDataPointer- ที่คล้ายกันมากที่จะยกเว้นก็ไม่ได้เรียกร้องโดยปริยายQSharedDataPointer detach()ฉันจะเรียกเวอร์ชัน 2.0 นี้QSharedDataPointerว่าการควบคุมที่เพิ่มขึ้นเล็กน้อยว่าเมื่อใดที่จะแยกออกหลังจากจำนวนอ้างอิงลดลงเป็นศูนย์โดยเฉพาะอย่างยิ่งไม่คุ้มค่ากับวัตถุใหม่ทั้งหมด

QSharedPointer- การนับการอ้างอิงอะตอม, เธรดปลอดภัย, ตัวชี้ที่แชร์ได้, การลบแบบกำหนดเอง (รองรับอาร์เรย์) ดูเหมือนทุกอย่างที่ตัวชี้อัจฉริยะควรจะเป็น นี่คือสิ่งที่ฉันใช้เป็นสมาร์ทพอยน์เตอร์ใน Qt เป็นหลักและฉันพบว่ามันเทียบได้กับboost:shared_ptrแม้ว่าอาจจะมีค่าใช้จ่ายมากกว่าอย่างมีนัยสำคัญเช่นหลายวัตถุใน Qt

QWeakPointer- คุณรู้สึกถึงรูปแบบที่เกิดซ้ำหรือไม่? เช่นเดียวกับstd::weak_ptrและboost::weak_ptrใช้ร่วมกับQSharedPointerเมื่อคุณต้องการการอ้างอิงระหว่างตัวชี้อัจฉริยะสองตัวที่อาจทำให้วัตถุของคุณไม่ถูกลบ

QScopedPointer- ชื่อนี้ควรดูคุ้นเคยและอันที่จริงแล้วนั้นมีพื้นฐานมาboost::scoped_ptrจากตัวชี้ที่ใช้ร่วมกันและจุดอ่อนของ Qt มันทำหน้าที่ในการจัดหาตัวชี้อัจฉริยะสำหรับเจ้าของคนเดียวโดยไม่มีค่าใช้จ่ายQSharedPointerซึ่งทำให้เหมาะสำหรับความเข้ากันได้มากขึ้นรหัสปลอดภัยข้อยกเว้นและทุกสิ่งที่คุณอาจใช้std::auto_ptrหรือboost::scoped_ptrสำหรับ


1
สองสิ่งที่ฉันคิดว่าควรค่าแก่การกล่าวถึง: intrusive_ptrโดยทั่วไปแล้วจะมีประสิทธิภาพมากกว่าshared_ptrเนื่องจากช่วยให้คุณมีการจัดสรรฮีปเดียวต่อวัตถุ shared_ptrในกรณีทั่วไปจะจัดสรรวัตถุฮีปขนาดเล็กแยกต่างหากสำหรับตัวนับอ้างอิง std::make_sharedสามารถใช้เพื่อให้ได้สิ่งที่ดีที่สุดจากทั้งสองโลก shared_ptrด้วยการจัดสรรฮีปเดียว
Arvid

ฉันอาจมีคำถามที่ไม่เกี่ยวข้อง: การเก็บขยะสามารถทำได้โดยเพียงแค่แทนที่พอยน์เตอร์ทั้งหมดด้วยshared_ptrs? (ไม่นับการแก้ไขการอ้างอิงตามวัฏจักร)
Seth Carnegie

@Seth Carnegie: ตัวชี้บางตัวจะไม่ชี้ไปที่สิ่งที่จัดสรรในร้านค้าฟรี
ในซิลิโค

2
@the_mandrill แต่จะใช้งานได้ถ้าตัวทำลายของคลาสการเป็นเจ้าของถูกกำหนดไว้ในหน่วยการแปลแยกต่างหาก (.cpp-file) กว่ารหัสไคลเอ็นต์ซึ่งใน Pimpl-idiom จะได้รับอย่างไรก็ตาม เนื่องจากหน่วยการแปลนี้มักจะรู้คำจำกัดความที่สมบูรณ์ของ Pimpl ดังนั้นตัวทำลายของมัน (เมื่อมันทำลาย auto_ptr) จะทำลาย Pimpl อย่างถูกต้อง ฉันก็กลัวเรื่องนี้เช่นกันเมื่อฉันเห็นคำเตือนเหล่านั้น แต่ฉันลองแล้วและมันได้ผล (ผู้ทำลายของ Pimpl ถูกเรียกมา) PS: โปรดใช้ @ -syntax เพื่อดูการตอบกลับ
Christian Rau

2
ประโยชน์ของรายการเพิ่มขึ้นโดยการเพิ่มลิงก์ที่เหมาะสมไปยังเอกสาร
ulidtko

5

นอกจากนี้ยังมีLokiที่ใช้ตัวชี้อัจฉริยะตามนโยบาย

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


1

นอกเหนือจากที่ให้มาแล้วยังมีสิ่งที่มุ่งเน้นด้านความปลอดภัยอีกด้วย:

SaferCPlusPlus

mse::TRefCountingPointerstd::shared_ptrคือการอ้างอิงนับตัวชี้สมาร์ทเช่น ความแตกต่างที่mse::TRefCountingPointerปลอดภัยกว่าเล็กกว่าและเร็วกว่า แต่ไม่มีกลไกความปลอดภัยของด้าย และมาในเวอร์ชัน "not null" และ "fixed" (non-retargetable) ซึ่งสามารถสันนิษฐานได้อย่างปลอดภัยว่าชี้ไปยังวัตถุที่จัดสรรอย่างถูกต้องเสมอ โดยพื้นฐานแล้วหากวัตถุเป้าหมายของคุณถูกแชร์ระหว่างเธรดแบบอะซิงโครนัสให้ใช้std::shared_ptrมิฉะนั้นmse::TRefCountingPointerจะเหมาะสมกว่า

mse::TScopeOwnerPointerคล้ายกับboost::scoped_ptrแต่ทำงานร่วมกับmse::TScopeFixedPointerใน "เข้มแข็งอ่อนแอ" ชนิดความสัมพันธ์ของตัวชี้ชอบและstd::shared_ptrstd::weak_ptr

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

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

นี่คือบทความที่อธิบายถึงสาเหตุและวิธีการใช้งาน (หมายเหตุปลั๊กไร้ยางอาย)

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