คุณต้องการใช้โค้ดลักษณะนี้ใน c ++ ภายใต้สถานการณ์ใด
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
คุณต้องการใช้โค้ดลักษณะนี้ใน c ++ ภายใต้สถานการณ์ใด
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
คำตอบ:
คุณต้องการส่งผ่านตัวชี้โดยการอ้างอิงหากคุณจำเป็นต้องแก้ไขตัวชี้แทนที่จะเป็นวัตถุที่ตัวชี้นั้นชี้ไป
ซึ่งคล้ายกับว่าทำไมถึงใช้พอยน์เตอร์คู่ การใช้ตัวชี้อ้างอิงจะปลอดภัยกว่าการใช้พอยน์เตอร์เล็กน้อย
delete
หรือเชื่อมโยงตัวชี้นั้นไปยังที่อื่นในหน่วยความจำ หรือว่าฉันเข้าใจผิด?
[]
โอเปอเรเตอร์ หนึ่งที่เป็นไปได้ (และในความเป็นจริงธรรมชาติ) const T &operator[](size_t index) const
ลายเซ็นนี้จะเป็น T &operator[](size_t index)
แต่คุณยังสามารถมี คุณสามารถมีทั้งสองอย่างในเวลาเดียวกัน หลังจะให้คุณทำสิ่งต่างๆเช่นmyArray[jj] = 42
. ในขณะเดียวกันคุณไม่ได้ให้ตัวชี้ไปยังข้อมูลของคุณดังนั้นผู้โทรจึงไม่สามารถยุ่งกับหน่วยความจำได้ (เช่นลบโดยไม่ได้ตั้งใจ)
50% ของโปรแกรมเมอร์ C ++ ชอบตั้งค่าพอยน์เตอร์เป็นโมฆะหลังจากการลบ:
template<typename T>
void moronic_delete(T*& p)
{
delete p;
p = nullptr;
}
หากไม่มีการอ้างอิงคุณจะเปลี่ยนสำเนาของตัวชี้ในเครื่องเท่านั้นโดยไม่ส่งผลกระทบต่อผู้โทร
paranoid_delete
moronic_delete
เขาอาจเป็นของอีก 50%;) อย่างไรก็ตามคำตอบสั้น ๆ ก็คือการตั้งค่าที่ชี้ไปที่ค่าว่างหลังจากdelete
นั้นแทบจะไม่มีประโยชน์เลย (เพราะมันควรจะอยู่นอกขอบเขตอยู่ดี) และมักขัดขวางการตรวจจับข้อบกพร่อง "ใช้หลังจากฟรี"
delete
โง่โดยทั่วไป ลูกสุนัขฉันทำ googling ฉันไม่เห็นว่าทำไมการลบถึงไร้ประโยชน์โดยสิ้นเชิง (บางทีฉันก็เป็นคนโง่เหมือนกันนะ;)) คุณช่วยอธิบายเพิ่มเติมหรือให้ลิงค์ได้ไหม
คำตอบของ David นั้นถูกต้อง แต่ถ้ายังเป็นนามธรรมอยู่เล็กน้อยนี่คือตัวอย่างสองตัวอย่าง:
คุณอาจต้องการให้ตัวชี้ที่เป็นอิสระทั้งหมดเป็นศูนย์เพื่อตรวจจับปัญหาหน่วยความจำก่อนหน้านี้ สไตล์ C ที่คุณทำ:
void freeAndZero(void** ptr)
{
free(*ptr);
*ptr = 0;
}
void* ptr = malloc(...);
...
freeAndZero(&ptr);
ใน C ++ ให้ทำเช่นเดียวกันคุณอาจทำ:
template<class T> void freeAndZero(T* &ptr)
{
delete ptr;
ptr = 0;
}
int* ptr = new int;
...
freeAndZero(ptr);
เมื่อจัดการกับรายการที่เชื่อมโยง - มักแสดงเป็นเพียงตัวชี้ไปยังโหนดถัดไป:
struct Node
{
value_t value;
Node* next;
};
ในกรณีนี้เมื่อคุณแทรกในรายการว่างคุณจำเป็นต้องเปลี่ยนตัวชี้ขาเข้าเนื่องจากผลลัพธ์ไม่ใช่NULL
ตัวชี้อีกต่อไป นี่เป็นกรณีที่คุณแก้ไขตัวชี้ภายนอกจากฟังก์ชันดังนั้นจะมีการอ้างอิงถึงตัวชี้ในลายเซ็น:
void insert(Node* &list)
{
...
if(!list) list = new Node(...);
...
}
มีตัวอย่างในคำถามนี้
ฉันต้องใช้รหัสแบบนี้เพื่อจัดเตรียมฟังก์ชันในการจัดสรรหน่วยความจำให้กับตัวชี้ที่ส่งผ่านและส่งคืนขนาดเนื่องจาก บริษัท ของฉัน "วัตถุ" ให้ฉันโดยใช้ STL
int iSizeOfArray(int* &piArray) {
piArray = new int[iNumberOfElements];
...
return iNumberOfElements;
}
ไม่ดี แต่ต้องส่งตัวชี้โดยอ้างอิง (หรือใช้ตัวชี้คู่) หากไม่เป็นเช่นนั้นหน่วยความจำจะถูกจัดสรรให้กับสำเนาภายในของตัวชี้หากมีการส่งผ่านค่าซึ่งส่งผลให้เกิดการรั่วไหลของหน่วยความจำ
ตัวอย่างหนึ่งคือเมื่อคุณเขียนฟังก์ชันตัวแยกวิเคราะห์และส่งตัวชี้แหล่งที่มาเพื่ออ่านจากถ้าฟังก์ชันนั้นควรจะดันตัวชี้นั้นไปข้างหลังอักขระตัวสุดท้ายซึ่งตัววิเคราะห์ได้รับการยอมรับอย่างถูกต้อง การใช้การอ้างอิงตัวชี้ทำให้ชัดเจนจากนั้นฟังก์ชันจะย้ายตัวชี้เดิมเพื่ออัปเดตตำแหน่ง
โดยทั่วไปคุณใช้การอ้างอิงถึงตัวชี้หากคุณต้องการส่งตัวชี้ไปยังฟังก์ชันและปล่อยให้ตัวชี้เดิมนั้นย้ายไปยังตำแหน่งอื่นแทนการย้ายสำเนาโดยไม่ส่งผลกระทบต่อต้นฉบับ
อีกสถานการณ์หนึ่งที่คุณอาจต้องการสิ่งนี้คือถ้าคุณมีคอลเลกชันของพอยน์เตอร์ stl และต้องการเปลี่ยนโดยใช้อัลกอริทึม stl ตัวอย่าง for_each ใน c ++ 98
struct Storage {
typedef std::list<Object*> ObjectList;
ObjectList objects;
void change() {
typedef void (*ChangeFunctionType)(Object*&);
std::for_each<ObjectList::iterator, ChangeFunctionType>
(objects.begin(), objects.end(), &Storage::changeObject);
}
static void changeObject(Object*& item) {
delete item;
item = 0;
if (someCondition) item = new Object();
}
};
มิฉะนั้นหากคุณใช้ลายเซ็นchangeObject (Object * item)คุณมีสำเนาของตัวชี้ไม่ใช่ต้นฉบับ