การจัดสรรตัวชี้ใหม่ให้ทำงานนั้นถูกกฎหมายหรือไม่


33

ตัวชี้ไปยังฟังก์ชันไม่ใช่ตัวชี้ข้อมูลธรรมดาเนื่องจากไม่สามารถเก็บไว้ในตัวชี้โมฆะ * อย่างไรก็ตามดูเหมือนว่าฉันสามารถเก็บสำเนาของตัวชี้ฟังก์ชั่นในหน่วยความจำแบบไดนามิก (ใน gcc และเสียงดังกราว) เช่นในรหัสด้านล่าง รหัสดังกล่าวถูกกฎหมายตามมาตรฐาน C ++ หรืออาจเป็นส่วนขยายคอมไพเลอร์บางส่วนหรือไม่

ยิ่งไปกว่านั้นตัวชี้ผลลัพธ์ไปยังฟังก์ชันตัวชี้ทำงานเป็นตัวชี้ข้อมูลธรรมดา: ฉันสามารถเก็บไว้ในโมฆะ * และดึงจากโมฆะ * โดย static_cast พฤติกรรมนี้รับประกันโดยมาตรฐานหรือไม่

int main()
{
  extern void fcn();
  void (*fcnPtr)() = &fcn;
  void (**ptrToFcnPtr)() = nullptr;

  //Make the copy of fcnPtr on the heap:
  ptrToFcnPtr = new decltype(fcnPtr)(fcnPtr);
  //Call the pointed-to function : 
  (**ptrToFcnPtr)();

  //Save the pointer in void* :
  void *ptr = ptrToFcnPtr;
  //retrieve the original ptr: 
  auto myPtr = static_cast< void(**)() > (ptr) ; 
  //free memory:
  delete ptrToFcnPtr ;

}

2
โปรดอย่าใช้ตัวชี้ funciton raw ใช้std::functionแทน
โปรแกรมเมอร์บางคนเพื่อน

คุณไม่จำเป็นต้องส่งไปยังnew ทำงานได้ดีเช่นกันเนื่องจากเป็นวัตถุไม่ใช่ฟังก์ชั่น void*void* ptr = &fcnPtr;fcnPtr
วอลนัท

5
@Someprogrammerdude std::functionเป็นคอนเทนเนอร์ที่ลบประเภทสำหรับการจัดเก็บ callable โดยพลการไม่ได้แทนตัวชี้ฟังก์ชั่นจริง ๆ ...
Michael Kenzel

7
(@Someprogrammerdude) std::functionกรุณาอย่าสุ่มสี่สุ่มห้าใช้ มันยอดเยี่ยมมากสำหรับความสามารถในการจัดเก็บฟังก์ชัน "polymorphic" (เช่นอะไรก็ตามที่มีลายเซ็นที่ถูกต้องแม้ว่าจะมีสถานะเหมือนในกรณีของ lambdas) แต่ก็เพิ่มค่าใช้จ่ายที่ไม่จำเป็น ตัวชี้ไปยังฟังก์ชันคือ POD std::functionไม่
Matthew

2
@ Matewew เพื่อความเป็นธรรมเอเดรียนจะถามเกี่ยวกับการจัดสรรตัวชี้ไปยังฟังก์ชั่นและชี้ไปที่มันด้วยการลบประเภทvoid*ดังนั้นในบริบทของคำถามนี้std::functionดูเหมือนจะเป็นสิ่งที่พวกเขากำลังมองหา ฉันยอมรับว่าการเลิกจ้างตัวชี้ฟังก์ชั่นทั่วไปของ SPD นั้นไม่ปลอดภัย
eerorika

คำตอบ:


27

ในขณะที่คำแนะนำการทำงานจะไม่คัดค้านชี้ "ชี้ไปยังฟังก์ชั่นบางชนิด" ยังคงเป็นชนิดของวัตถุ[basic.types] / 8 ดังนั้นพอยน์เตอร์ของฟังก์ชั่นจึงเป็นวัตถุเองสิ่งที่พวกมันชี้ไปนั้นไม่ใช่

ดังนั้นคุณสามารถสร้างวัตถุประเภทตัวชี้ฟังก์ชั่นผ่านการแสดงออกใหม่ ...


9

เนื่องจากไม่สามารถจัดเก็บไว้ในพอยน์เตอร์ของฟังก์ชัน (พอยน์เตอร์พอยน์เตอร์) ในตัวชี้ void *

ที่จริงแล้วการจัดเก็บตัวชี้ฟังก์ชันตามที่void*ได้รับการสนับสนุนตามเงื่อนไข ซึ่งหมายความว่าสามารถหรือไม่สามารถจัดเก็บขึ้นอยู่กับการใช้ภาษา หากการใช้ภาษารองรับการโหลดแบบไดนามิกการแปลงตัวชี้ฟังก์ชันในvoid*อาจได้รับการสนับสนุน GCC, Clang และ MSVC สนับสนุนทั้งหมดนี้:

reinterpret_cast<void*>(&function);

การจัดสรรตัวชี้ใหม่ให้ทำงานนั้นถูกกฎหมายหรือไม่

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

นอกจากนี้ตัวชี้ผลลัพธ์ไปยังตัวชี้ฟังก์ชันจะทำงานเป็นตัวชี้ข้อมูลธรรมดา

ตัวชี้ฟังก์ชั่นเป็นวัตถุ ตัวชี้ไปยังตัวชี้ฟังก์ชันไม่เพียง "ทำงานเป็น" แต่เป็นตัวชี้ไปยังวัตถุ

ฉันสามารถเก็บไว้ในโมฆะ * และดึงจากโมฆะ * โดย static_cast พฤติกรรมนี้รับประกันโดยมาตรฐานหรือไม่

อนุญาตให้ทำการแปลงระหว่างตัวชี้เป็นโมฆะและตัวชี้เป็นวัตถุได้ และการแปลงแบบไปกลับรับประกันว่าจะให้ตัวชี้ดั้งเดิม


ขอบคุณ แต่จากนั้นการแปลง function-pointer เป็นโมฆะ * (หรือวิธีอื่น ๆ ) ฉันต้องใช้ reinterpret_cast ใช่ไหม?
เอเดรียน

1
@Adrian ใช่ ฉันเพิ่มตัวอย่าง
eerorika

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