ตัวชี้อัจฉริยะคืออะไรและควรใช้เมื่อใด
ตัวชี้อัจฉริยะคืออะไรและควรใช้เมื่อใด
คำตอบ:
UPDATE
คำตอบนี้ค่อนข้างเก่าและอธิบายสิ่งที่ 'ดี' ในเวลานั้นซึ่งเป็นตัวชี้สมาร์ทที่ได้รับจากห้องสมุด Boost ตั้งแต่ C ++ 11, ไลบรารีมาตรฐานได้จัดเตรียมพอยน์เตอร์พอยน์เตอร์ให้เพียงพอ, ดังนั้นคุณควรใช้และstd::unique_ptr
, .std::shared_ptr
std::weak_ptr
std::auto_ptr
นอกจากนี้ยังมี มันเป็นเหมือนตัวชี้ที่กำหนดขอบเขตยกเว้นว่ามันมีความสามารถที่เป็นอันตราย "พิเศษ" ที่จะคัดลอกซึ่งยังโอนความเป็นเจ้าของโดยไม่คาดคิด
มันเลิกใช้แล้วใน C ++ 11 และนำออกใน C ++ 17ดังนั้นคุณไม่ควรใช้
std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership.
// p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.
คำตอบเดิม ๆ
ตัวชี้สมาร์ทเป็นคลาสที่ล้อมรอบตัวชี้ C ++ แบบ 'ดิบ' (หรือ 'เปล่า') เพื่อจัดการอายุการใช้งานของวัตถุที่ถูกชี้ไป ไม่มีประเภทตัวชี้สมาร์ทเดียว แต่พวกเขาทั้งหมดพยายามที่จะทำให้ตัวชี้แบบดิบ ๆ เป็นจริงในทางปฏิบัติ
ตัวชี้สมาร์ทควรเป็นที่ต้องการมากกว่าตัวชี้แบบดิบ ถ้าคุณรู้สึกว่าคุณต้องใช้พอยน์เตอร์ (ก่อนอื่นให้พิจารณาถ้าคุณทำจริงๆ ) โดยปกติแล้วคุณต้องการใช้พอยน์เตอร์สมาร์ทเพราะมันจะช่วยบรรเทาปัญหามากมายที่เกิดขึ้นกับพอยน์เตอร์พอยน์เตอร์
ด้วยตัวชี้แบบดิบโปรแกรมเมอร์ต้องทำลายวัตถุอย่างชัดเจนเมื่อไม่มีประโยชน์อีกต่อไป
// Need to create the object to achieve some goal
MyObject* ptr = new MyObject();
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?
ตัวชี้สมาร์ทโดยการเปรียบเทียบกำหนดนโยบายว่าเมื่อวัตถุถูกทำลาย คุณยังต้องสร้างวัตถุ แต่คุณไม่ต้องกังวลกับการทำลายมันอีกต่อไป
SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.
// Destruction of the object happens, depending
// on the policy the smart pointer class uses.
// Destruction would happen even if DoSomething()
// raises an exception
นโยบายที่ง่ายในการใช้งานที่เกี่ยวข้องกับขอบเขตของวัตถุชี้เสื้อคลุมสมาร์ทเช่นดำเนินการโดยหรือboost::scoped_ptr
std::unique_ptr
void f()
{
{
std::unique_ptr<MyObject> ptr(new MyObject());
ptr->DoSomethingUseful();
} // ptr goes out of scope --
// the MyObject is automatically destroyed.
// ptr->Oops(); // Compile error: "ptr" not defined
// since it is no longer in scope.
}
โปรดทราบว่าstd::unique_ptr
ไม่สามารถคัดลอกอินสแตนซ์ได้ สิ่งนี้ป้องกันไม่ให้ตัวชี้ถูกลบหลายครั้ง (ไม่ถูกต้อง) อย่างไรก็ตามคุณสามารถส่งต่อการอ้างอิงไปยังฟังก์ชันอื่นที่คุณโทรได้
std::unique_ptr
s มีประโยชน์เมื่อคุณต้องการผูกอายุการใช้งานของวัตถุกับบล็อกของรหัสเฉพาะหรือถ้าคุณฝังเป็นข้อมูลสมาชิกภายในวัตถุอื่นอายุการใช้งานของวัตถุอื่น มีวัตถุอยู่จนกระทั่งบล็อกที่มีรหัสถูกออกหรือจนกว่าวัตถุที่บรรจุนั้นจะถูกทำลาย
นโยบายตัวชี้สมาร์ทที่ซับซ้อนยิ่งขึ้นเกี่ยวข้องกับการนับการอ้างอิงตัวชี้ นี่เป็นการอนุญาตให้ตัวชี้ถูกคัดลอก เมื่อ "การอ้างอิง" สุดท้ายไปยังวัตถุถูกทำลายวัตถุจะถูกลบ นโยบายนี้จะดำเนินการโดยและboost::shared_ptr
std::shared_ptr
void f()
{
typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
MyObjectPtr p1; // Empty
{
MyObjectPtr p2(new MyObject());
// There is now one "reference" to the created object
p1 = p2; // Copy the pointer.
// There are now two references to the object.
} // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero.
// The object is deleted.
พอยน์เตอร์ที่นับตามการอ้างอิงนั้นมีประโยชน์มากเมื่ออายุการใช้งานของวัตถุของคุณซับซ้อนกว่ามากและไม่ได้เชื่อมโยงโดยตรงกับส่วนใดส่วนหนึ่งของรหัสหรือวัตถุอื่น
มีหนึ่งอุปสรรคในการอ้างอิงพอยน์เตอร์นับ - ความเป็นไปได้ของการสร้างการอ้างอิงห้อย:
// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!
ความเป็นไปได้อีกอย่างก็คือการสร้างการอ้างอิงแบบวงกลม:
struct Owner {
std::shared_ptr<Owner> other;
};
std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1
// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!
เมื่อต้องการแก้ไขปัญหานี้ทั้ง Boost และ C ++ 11 ได้กำหนดweak_ptr
ที่จะกำหนดอ่อนแอ (ไม่ได้นับ) shared_ptr
อ้างอิงถึง
std::auto_ptr<MyObject> p1 (new MyObject());
แทนstd::auto_ptr<MyObject> p1 (new Owner());
?
const std::auto_ptr
ปลอดภัยที่จะใช้ถ้าคุณติดอยู่กับ C ++ 03 ฉันใช้มันสำหรับรูปแบบ pimpl ค่อนข้างมากจนกระทั่งฉันได้เข้าถึง C ++ 11
นี่คือคำตอบง่ายๆสำหรับยุคปัจจุบันของ C ++ (C ++ 11 และใหม่กว่า):
std::unique_ptr
เมื่อคุณไม่ต้องการถือการอ้างอิงหลายรายการกับวัตถุเดียวกัน ตัวอย่างเช่นใช้สำหรับตัวชี้ไปยังหน่วยความจำซึ่งได้รับการจัดสรรในการเข้าสู่ขอบเขตและยกเลิกการจัดสรรเมื่อออกจากขอบเขตstd::shared_ptr
เมื่อคุณต้องการอ้างถึงวัตถุของคุณจากหลาย ๆ ที่ - และไม่ต้องการให้วัตถุของคุณถูกจัดสรรคืนจนกว่าการอ้างอิงทั้งหมดเหล่านี้จะหายไปเองstd::weak_ptr
เมื่อคุณต้องการอ้างถึงวัตถุของคุณจากหลาย ๆ ที่ - สำหรับการอ้างอิงที่ไม่สนใจและยกเลิกการจัดสรร (ดังนั้นพวกเขาจะเพิ่งทราบว่าวัตถุนั้นหายไปเมื่อคุณพยายามอ้างถึง)boost::
ตัวชี้อัจฉริยะหรือstd::auto_ptr
ยกเว้นในกรณีพิเศษที่คุณสามารถอ่านได้หากคุณต้องการT*
คือstd::unique_ptr<T>
สิ่งที่std::weak_ptr<T>
จะเป็นstd::shared_ptr<T>
ตัวชี้สมาร์ทเป็นชนิดที่คล้ายกับตัวชี้พร้อมฟังก์ชันเพิ่มเติมบางอย่างเช่นการจัดสรรคืนหน่วยความจำอัตโนมัติการนับการอ้างอิงเป็นต้น
อินโทรขนาดเล็กมีอยู่ในหน้าสมาร์ทพอยน์เตอร์ - อะไร, ทำไม, ซึ่ง? .
หนึ่งในประเภทสมาร์ทพอยน์เตอร์แบบง่ายคือstd::auto_ptr
(บทที่ 20.4.5 ของมาตรฐาน C ++) ซึ่งช่วยให้สามารถจัดสรรคืนหน่วยความจำโดยอัตโนมัติเมื่ออยู่นอกขอบเขตและมีความแข็งแกร่งกว่าการใช้พอยน์เตอร์แบบง่ายเมื่อข้อยกเว้นถูกโยน
อีกประเภทที่สะดวกคือboost::shared_ptr
ใช้การนับการอ้างอิงและยกเลิกการจัดสรรหน่วยความจำโดยอัตโนมัติเมื่อไม่มีการอ้างอิงไปยังวัตถุ นี้จะช่วยให้หลีกเลี่ยงการรั่วไหลของหน่วยความจำและเป็นเรื่องง่ายที่จะใช้ในการดำเนินการRAII
หัวเรื่องถูกครอบคลุมในเชิงลึกในหนังสือ"เทมเพลต C ++: คู่มือฉบับสมบูรณ์" โดย David Vandevoorde, Nicolai M. Josuttis , บทที่ 20 บทที่สมาร์ทพอยน์เตอร์ บางหัวข้อครอบคลุม:
std::auto_ptr
ถูกเลิกใช้และไม่สนับสนุนอย่างมากเนื่องจากคุณสามารถถ่ายโอนความเป็นเจ้าของโดยไม่ได้ตั้งใจ - C ++ 11 เอาความต้องการของ Boost, การใช้งาน: std::unique_ptr
, std::shared_ptr
และstd::weak_ptr
คำจำกัดความที่จัดทำโดย Chris, Sergdev และ Llyod นั้นถูกต้อง ฉันชอบคำจำกัดความที่ง่ายกว่า แต่เพื่อให้ชีวิตของฉันง่ายขึ้น: ตัวชี้ที่ชาญฉลาดเป็นเพียงคลาสที่เกินพิกัด->
และ*
ตัวดำเนินการ ซึ่งหมายความว่าวัตถุของคุณมีความหมายคล้ายกับตัวชี้ แต่คุณสามารถทำให้สิ่งต่าง ๆ น่าสนใจรวมถึงการนับการอ้างอิงการทำลายอัตโนมัติเป็นต้น
shared_ptr
และauto_ptr
เพียงพอในกรณีส่วนใหญ่ แต่มาพร้อมกับชุดนิสัยแปลก ๆ
ตัวชี้สมาร์ทนั้นเหมือนตัวชี้ปกติ (พิมพ์) เช่น "char *" ยกเว้นเมื่อตัวชี้นั้นออกนอกขอบเขตสิ่งที่ชี้ไปจะถูกลบเช่นกัน คุณสามารถใช้งานได้เหมือนตัวชี้ปกติโดยใช้ "->" แต่ไม่จำเป็นถ้าคุณต้องการตัวชี้ที่แท้จริงไปยังข้อมูล เพื่อที่คุณสามารถใช้ "& * ptr"
มันมีประโยชน์สำหรับ:
วัตถุที่ต้องจัดสรรใหม่ แต่คุณต้องการมีอายุการใช้งานเท่ากับของบางอย่างในสแต็กนั้น หากวัตถุถูกกำหนดให้กับตัวชี้สมาร์ทแล้วพวกเขาจะถูกลบเมื่อโปรแกรมออกจากฟังก์ชั่น / บล็อก
ข้อมูลสมาชิกของคลาสดังนั้นเมื่อวัตถุถูกลบข้อมูลที่เป็นเจ้าของทั้งหมดจะถูกลบเช่นกันโดยไม่มีรหัสพิเศษใด ๆ ใน destructor (คุณจะต้องแน่ใจว่า destructor นั้นเสมือนจริงซึ่งเป็นสิ่งที่ดีที่จะทำ) .
คุณอาจไม่ต้องการใช้ตัวชี้สมาร์ทเมื่อ:
ดูสิ่งนี้ด้วย:
พอยน์เตอร์สมาร์ทชนิดต่าง ๆ ส่วนใหญ่จัดการการกำจัดของตัวชี้ไปยังวัตถุสำหรับคุณ. มีประโยชน์มากเพราะคุณไม่ต้องคิดเกี่ยวกับการกำจัดวัตถุด้วยตนเองอีกต่อไป
ส่วนใหญ่ที่ใช้กันทั่วไปสมาร์ทชี้std::tr1::shared_ptr
(หรือboost::shared_ptr
) std::auto_ptr
และน้อยกว่าปกติ shared_ptr
ผมขอแนะนำให้ใช้งานปกติของ
shared_ptr
มีความหลากหลายมากและจัดการกับสถานการณ์การกำจัดที่หลากหลายรวมถึงกรณีที่วัตถุต้อง "ผ่านข้ามขอบเขต DLL" (กรณีฝันร้ายทั่วไปหากlibc
มีการใช้ s ที่แตกต่างกันระหว่างรหัสและ DLL ของคุณ)
ตัวชี้สมาร์ทเป็นวัตถุที่ทำหน้าที่เหมือนตัวชี้ แต่ยังให้การควบคุมในการก่อสร้างการทำลายการคัดลอกการย้ายและการยกเลิกการอ้างอิง
หนึ่งสามารถใช้ตัวชี้สมาร์ทของตัวเอง แต่ห้องสมุดหลายแห่งยังให้การใช้งานตัวชี้สมาร์ทแต่ละคนมีข้อดีและข้อเสียที่แตกต่างกัน
ตัวอย่างเช่นBoostให้การใช้งานตัวชี้สมาร์ทต่อไปนี้:
shared_ptr<T>
เป็นตัวชี้การT
ใช้การนับการอ้างอิงเพื่อกำหนดว่าเมื่อใดที่วัตถุไม่ต้องการอีกต่อไปscoped_ptr<T>
เป็นตัวชี้ที่ถูกลบโดยอัตโนมัติเมื่อออกนอกขอบเขต ไม่สามารถกำหนดได้intrusive_ptr<T>
เป็นอีกหนึ่งตัวชี้การนับการอ้างอิง มันให้ประสิทธิภาพที่ดีกว่าshared_ptr
แต่ต้องการประเภทT
เพื่อให้กลไกการนับการอ้างอิงของตัวเองweak_ptr<T>
เป็นตัวชี้ที่อ่อนแอทำงานร่วมกับshared_ptr
เพื่อหลีกเลี่ยงการอ้างอิงแบบวงกลมshared_array<T>
เป็นเหมือนแต่สำหรับอาร์เรย์shared_ptr
T
scoped_array<T>
เป็นเหมือนแต่สำหรับอาร์เรย์scoped_ptr
T
เหล่านี้เป็นเพียงคำอธิบายเชิงเส้นของแต่ละคำและสามารถใช้ตามต้องการได้สำหรับรายละเอียดเพิ่มเติมและตัวอย่างหนึ่งสามารถดูเอกสารของ Boost
นอกจากนี้ไลบรารีมาตรฐาน C ++ ยังมีตัวชี้อัจฉริยะสามตัว std::unique_ptr
สำหรับเจ้าของที่ไม่ซ้ำกันสำหรับเจ้าของร่วมกันและstd::shared_ptr
มีอยู่ใน C ++ 03 แต่ขณะนี้เลิกใช้แล้วstd::weak_ptr
std::auto_ptr
scoped_ptr
ไม่เหมือนประกาศในพื้นที่const unique_ptr
- ซึ่งจะถูกลบออกเมื่อออกจากขอบเขต
นี่คือลิงค์สำหรับคำตอบที่คล้ายกัน: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
ตัวชี้สมาร์ทเป็นวัตถุที่ทำหน้าที่ดูและรู้สึกเหมือนตัวชี้ปกติ แต่มีฟังก์ชั่นเพิ่มเติม ใน C ++ สมาร์ทพอยน์เตอร์จะถูกใช้เป็นเทมเพลตคลาสที่ห่อหุ้มตัวชี้และแทนที่ตัวดำเนินการตัวชี้มาตรฐาน พวกเขามีข้อได้เปรียบมากกว่าพอยน์เตอร์ทั่วไป จะรับประกันว่าจะถูกเตรียมใช้งานเป็นพอยน์เตอร์พอยน์เตอร์หรือพอยน์เตอร์ไปยังวัตถุฮีป ตรวจสอบการเปลี่ยนทิศทางผ่านตัวชี้ null ไม่จำเป็นต้องลบ วัตถุจะถูกทำให้เป็นอิสระโดยอัตโนมัติเมื่อตัวชี้สุดท้ายของพวกมันหายไป ปัญหาสำคัญอย่างหนึ่งของพอยน์เตอร์อัจฉริยะเหล่านี้คือไม่เหมือนกับพอยน์เตอร์ทั่วไปพวกเขาไม่เคารพมรดก ตัวชี้สมาร์ทไม่น่าสนใจสำหรับรหัส polymorphic รับด้านล่างเป็นตัวอย่างสำหรับการใช้งานของตัวชี้สมาร์ท
ตัวอย่าง:
template <class X>
class smart_pointer
{
public:
smart_pointer(); // makes a null pointer
smart_pointer(const X& x) // makes pointer to copy of x
X& operator *( );
const X& operator*( ) const;
X* operator->() const;
smart_pointer(const smart_pointer <X> &);
const smart_pointer <X> & operator =(const smart_pointer<X>&);
~smart_pointer();
private:
//...
};
คลาสนี้ใช้ตัวชี้สมาร์ทกับวัตถุประเภท X วัตถุนั้นอยู่ในฮีป นี่คือวิธีการใช้งาน:
smart_pointer <employee> p= employee("Harris",1333);
เช่นเดียวกับตัวดำเนินการโอเวอร์โหลดอื่น ๆ p จะทำงานเหมือนตัวชี้ปกติ
cout<<*p;
p->raise_salary(0.5);
http://en.wikipedia.org/wiki/Smart_pointer
ในวิทยาการคอมพิวเตอร์ตัวชี้อัจฉริยะเป็นชนิดข้อมูลนามธรรมที่จำลองตัวชี้ในขณะที่ให้คุณสมบัติเพิ่มเติมเช่นการรวบรวมขยะอัตโนมัติหรือการตรวจสอบขอบเขต คุณสมบัติเพิ่มเติมเหล่านี้มีจุดประสงค์เพื่อลดข้อบกพร่องที่เกิดจากการใช้งานพอยน์เตอร์ในทางที่ผิดขณะเดียวกันก็รักษาประสิทธิภาพไว้ ตัวชี้สมาร์ทมักจะติดตามวัตถุที่ชี้ไปที่พวกเขาเพื่อวัตถุประสงค์ในการจัดการหน่วยความจำ การใช้พอยน์เตอร์ในทางที่ผิดเป็นแหล่งสำคัญของข้อบกพร่อง: การจัดสรรคงที่การจัดสรรคืนและการอ้างอิงที่ต้องดำเนินการโดยโปรแกรมที่เขียนโดยใช้พอยน์เตอร์ทำให้มีโอกาสมากที่หน่วยความจำรั่วไหลจะเกิดขึ้น ตัวชี้สมาร์ทพยายามป้องกันการรั่วไหลของหน่วยความจำโดยทำให้การจัดสรรคืนทรัพยากรอัตโนมัติ: เมื่อตัวชี้ไปยังวัตถุ (หรือตัวสุดท้ายในชุดตัวชี้) ถูกทำลาย
ให้ T เป็นคลาสในตัวชี้การสอนนี้ใน C ++ สามารถแบ่งออกเป็น 3 ประเภท:
1) ตัวชี้ดิบ :
T a;
T * _ptr = &a;
พวกเขาเก็บที่อยู่หน่วยความจำไปยังตำแหน่งในหน่วยความจำ ใช้ด้วยความระมัดระวังเนื่องจากโปรแกรมซับซ้อนยากต่อการติดตาม
ตัวชี้ที่มีข้อมูล const หรือที่อยู่ {อ่านย้อนหลัง}
T a ;
const T * ptr1 = &a ;
T const * ptr1 = &a ;
ชี้ไปยังชนิดข้อมูล T ซึ่งเป็นค่าคงที่ หมายความว่าคุณไม่สามารถเปลี่ยนชนิดข้อมูลโดยใช้ตัวชี้ เช่น*ptr1 = 19
; จะไม่ทำงาน. แต่คุณสามารถย้ายตัวชี้ เช่นptr1++ , ptr1--
; ฯลฯ จะทำงาน อ่านย้อนหลัง: ตัวชี้เพื่อพิมพ์ T ซึ่งเป็น const
T * const ptr2 ;
ตัวชี้ const ไปยังชนิดข้อมูล T หมายความว่าคุณไม่สามารถย้ายตัวชี้ได้ แต่คุณสามารถเปลี่ยนค่าที่ตัวชี้ชี้ไปได้ เช่น*ptr2 = 19
จะทำงานได้ แต่ptr2++ ; ptr2--
จะไม่ทำงาน อ่านย้อนหลัง: ตัวชี้ const ไปยังประเภท T
const T * const ptr3 ;
ตัวชี้ const ไปยัง const ข้อมูลชนิด T หมายความว่าคุณไม่สามารถย้ายตัวชี้ไม่สามารถเปลี่ยนตัวชี้ชนิดข้อมูลเป็นตัวชี้ได้ เช่น ptr3-- ; ptr3++ ; *ptr3 = 19;
จะไม่ทำงาน
3) ตัวชี้อัจฉริยะ : { #include <memory>
}
ตัวชี้ที่ใช้ร่วมกัน :
T a ;
//shared_ptr<T> shptr(new T) ; not recommended but works
shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe
std::cout << shptr.use_count() ; // 1 // gives the number of "
things " pointing to it.
T * temp = shptr.get(); // gives a pointer to object
// shared_pointer used like a regular pointer to call member functions
shptr->memFn();
(*shptr).memFn();
//
shptr.reset() ; // frees the object pointed to be the ptr
shptr = nullptr ; // frees the object
shptr = make_shared<T>() ; // frees the original object and points to new object
ดำเนินการโดยใช้การอ้างอิงเพื่อติดตามจำนวน "สิ่ง" ที่ชี้ไปยังวัตถุที่ชี้โดยตัวชี้ เมื่อจำนวนนี้ไปที่ 0 วัตถุจะถูกลบโดยอัตโนมัติเช่นวัตถุจะถูกลบเมื่อ share_ptr ทั้งหมดที่ชี้ไปยังวัตถุนั้นอยู่นอกขอบเขต การทำเช่นนี้จะช่วยขจัดอาการปวดหัวจากการต้องลบวัตถุที่คุณได้จัดสรรไว้โดยใช้สิ่งใหม่
ตัวชี้ที่อ่อนแอ: ช่วยจัดการกับการอ้างอิงแบบวนซึ่งเกิดขึ้นเมื่อใช้ตัวชี้ที่ใช้ร่วมกันหากคุณมีวัตถุสองตัวชี้ไปที่ตัวชี้ที่ใช้ร่วมกันสองตัวและมีตัวชี้ที่ใช้ร่วมกันภายในชี้ไปที่ตัวชี้ที่ใช้ร่วมกัน ถูกลบเมื่อตัวชี้ที่ใช้ร่วมกันออกนอกขอบเขต ในการแก้ปัญหานี้ให้เปลี่ยนสมาชิกภายในจาก shared_ptr เป็น weak_ptr หมายเหตุ: ในการเข้าถึงองค์ประกอบที่ชี้โดยตัวชี้จุดอ่อนใช้การล็อค () สิ่งนี้จะส่งกลับค่า weak_ptr
T a ;
shared_ptr<T> shr = make_shared<T>() ;
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr
wk.lock()->memFn() ; // use lock to get a shared_ptr
// ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access
ดู: std :: weak_ptr มีประโยชน์เมื่อใด?
Unique Pointer: ตัวชี้อัจฉริยะที่มีน้ำหนักเบาพร้อมความเป็นเจ้าของ ใช้เมื่อตัวชี้ชี้ไปที่วัตถุที่ไม่ซ้ำกันโดยไม่แบ่งปันวัตถุระหว่างตัวชี้
unique_ptr<T> uptr(new T);
uptr->memFn();
//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr
ในการเปลี่ยนวัตถุที่ชี้ไปตาม PTR ที่ไม่ซ้ำกันให้ใช้ซีแมนทิกส์ของการย้าย
unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1);
// object pointed by uptr2 is deleted and
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null
การอ้างอิง: โดยพื้นฐานแล้วพวกมันอาจจะเป็นตัวชี้ const เช่นตัวชี้ซึ่งเป็น const และไม่สามารถย้ายด้วยไวยากรณ์ที่ดีกว่า
ดู: อะไรคือความแตกต่างระหว่างตัวแปรตัวชี้และตัวแปรอ้างอิงใน C ++?
r-value reference : reference to a temporary object
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified
การอ้างอิง: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ ขอบคุณ Andre สำหรับการชี้ให้เห็นคำถามนี้
ตัวชี้สมาร์ทเป็นชั้นเรียนซึ่งเป็นเสื้อคลุมของตัวชี้ปกติ แตกต่างจากพอยน์เตอร์ปกติวงจรชีวิตของจุดอัจฉริยะขึ้นอยู่กับจำนวนการอ้างอิง (กี่ครั้งที่มีการกำหนดวัตถุตัวชี้อัจฉริยะ) ดังนั้นเมื่อใดก็ตามที่ตัวชี้สมาร์ทถูกกำหนดให้กับอีกคนหนึ่งจำนวนการอ้างอิงภายในบวกบวก และเมื่อใดก็ตามที่วัตถุออกจากขอบเขตการนับการอ้างอิงลบด้วย
ตัวชี้อัตโนมัติแม้ว่าจะดูคล้ายกันจะต่างจากตัวชี้สมาร์ทโดยสิ้นเชิง มันเป็นคลาสที่สะดวกสบายที่จัดสรรคืนทรัพยากรเมื่อใดก็ตามที่วัตถุตัวชี้อัตโนมัติดับขอบเขตตัวแปร ในระดับหนึ่งจะทำให้ตัวชี้ (ไปยังหน่วยความจำที่จัดสรรแบบไดนามิก) ทำงานคล้ายกับตัวแปรสแต็ก (จัดสรรแบบคงที่ในเวลารวบรวม)
ตัวชี้อัจฉริยะคือสิ่งที่คุณไม่ต้องกังวลเกี่ยวกับการจัดสรรหน่วยความจำการแบ่งปันทรัพยากรและการถ่ายโอน
คุณสามารถใช้ตัวชี้เหล่านี้ได้ในลักษณะเดียวกันกับการจัดสรรใด ๆ ใน Java ในจาวา Garbage Collector ทำกลอุบายในขณะที่ใน Smart Pointers กลอุบายทำโดย Destructors
คำตอบที่มีอยู่นั้นดี แต่ไม่ครอบคลุมถึงสิ่งที่ต้องทำเมื่อตัวชี้สมาร์ทไม่ใช่คำตอบ (สมบูรณ์) ของปัญหาที่คุณพยายามแก้ไข
เหนือสิ่งอื่นใด (อธิบายได้ดีในคำตอบอื่น ๆ ) การใช้ตัวชี้สมาร์ทเป็นวิธีแก้ปัญหาที่เป็นไปได้เราจะใช้คลาสนามธรรมเป็นชนิดส่งคืนฟังก์ชันได้อย่างไร ซึ่งทำเครื่องหมายว่าซ้ำกับคำถามนี้ อย่างไรก็ตามคำถามแรกที่ถามว่าอยากให้ระบุคลาสพื้นฐาน (หรืออันใดอันหนึ่ง) ในรูปแบบ return ใน C ++ คือ "คุณหมายถึงอะไรจริง ๆ " มีการสนทนาที่ดี (พร้อมการอ้างอิงเพิ่มเติม) ของการเขียนโปรแกรมเชิงวัตถุเชิงสำนวนใน C ++ (และวิธีนี้แตกต่างกับภาษาอื่น ๆ ) ในเอกสารประกอบของไลบรารีตัวชี้บูสเตอร์คอนเทนเนอร์. โดยสรุปใน C ++ คุณต้องคิดถึงความเป็นเจ้าของ พอยน์เตอร์อัจฉริยะตัวใดที่ช่วยคุณ แต่ไม่ใช่โซลูชันเดียวหรือเป็นโซลูชั่นที่สมบูรณ์เสมอ (ไม่ได้ให้สำเนาที่หลากหลาย) และไม่ได้เป็นโซลูชันที่คุณต้องการเปิดเผยในส่วนต่อประสานของคุณเสมอ (และฟังก์ชั่นคืนเสียงน่ากลัว มากเหมือนอินเทอร์เฟซ) มันอาจจะเพียงพอที่จะกลับมาอ้างอิงเช่น แต่ในทุกกรณีเหล่านี้ (ชี้สมาร์ทชี้ภาชนะหรือเพียงแค่กลับอ้างอิง) คุณมีการเปลี่ยนแปลงกลับมาจากการที่ค่ารูปแบบของบางอ้างอิง หากคุณต้องการคัดลอกคุณอาจต้องเพิ่ม "idiom" สำเร็จรูปมากขึ้นหรือย้ายเกิน OOP (หรือมิฉะนั้น) OOP ใน C ++ เพื่อ polymorphism ทั่วไปมากขึ้นโดยใช้ห้องสมุดเช่นAdobe PolyหรือBoost.TypeErasure.