Có hợp pháp để phân bổ mới một con trỏ để hoạt động không?


33

Con trỏ tới các hàm không phải là con trỏ dữ liệu đơn giản vì chúng không thể được lưu trữ trong một con trỏ void *. Tuy nhiên, dường như tôi có thể lưu trữ bản sao của một con trỏ hàm trong bộ nhớ động (trong gcc và clang) như trong mã dưới đây. Là một mã như vậy hợp pháp theo Tiêu chuẩn C ++, hoặc có thể đây là một loại phần mở rộng trình biên dịch?

Hơn nữa, con trỏ kết quả đến con trỏ hàm hoạt động như một con trỏ dữ liệu đơn giản: Tôi có thể lưu trữ nó trong void * và truy xuất nó từ void * bởi static_cast. Là hành vi này được đảm bảo bởi Tiêu chuẩn?

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
Vui lòng không sử dụng con trỏ funciton thô. Sử dụng std::functionthay thế.
Một số lập trình viên anh chàng

Bạn không cần phải newchọn void*. void* ptr = &fcnPtr;cũng hoạt động tốt, vì fcnPtrlà một đối tượng, không phải là một chức năng.
quả óc chó

5
@Someprogrammerdude std::functionlà một thùng chứa loại để lưu trữ một cuộc gọi tùy ý, không thực sự thay thế cho các con trỏ hàm chức năng
Michael Kenzel

7
(@Someprogrammerdude) Vui lòng không sử dụng / đề nghị một cách mù quáng std::function. Thật tuyệt vời vì khả năng lưu trữ các chức năng "đa hình" (nghĩa là bất cứ thứ gì có chữ ký phù hợp, ngay cả khi nó có trạng thái như trong trường hợp của một số lambdas), nhưng điều đó cũng bổ sung thêm chi phí có thể không cần thiết. Một con trỏ tới một hàm là POD. A std::functionthì không.
Matthew

2
@Matthew Để công bằng, Adrian đang hỏi về việc phân bổ động con trỏ để hoạt động và chỉ vào nó với một kiểu xóa void*, vì vậy trong bối cảnh của câu hỏi này std::functiondường như chính xác là những gì họ đang tìm kiếm. Tôi đồng ý rằng việc sa thải chức năng chung của SPD là không có cơ sở.
eerorika

Câu trả lời:


27

Trong khi các con trỏ hàm không phải là con trỏ đối tượng, "con trỏ tới hàm của một số loại" vẫn là một loại đối tượng [basic.types] / 8 . Vì vậy, các con trỏ hàm là chính các đối tượng, chỉ có điều chúng trỏ đến là không.

Vì vậy, bạn chắc chắn có thể tạo một đối tượng của kiểu con trỏ hàm thông qua một biểu thức mới.


9

vì chúng (con trỏ hàm) không thể được lưu trữ trong một con trỏ void *.

Trên thực tế, việc lưu trữ một con trỏ hàm như là một void*điều kiện được hỗ trợ. Điều này có nghĩa là nó có thể hoặc không thể được lưu trữ tùy thuộc vào việc thực hiện ngôn ngữ. Nếu việc triển khai ngôn ngữ hỗ trợ tải động, thì có thể chuyển đổi con trỏ hàm trong void*. GCC, Clang và MSVC đều hỗ trợ điều này:

reinterpret_cast<void*>(&function);

Có hợp pháp để phân bổ mới một con trỏ để hoạt động không?

Chắc chắn rồi. Tất cả các con trỏ, bao gồm các con trỏ hàm, là các đối tượng và tất cả các đối tượng có thể được phân bổ động.

Ngoài ra, con trỏ kết quả đến con trỏ hàm hoạt động như một con trỏ dữ liệu đơn giản

Con trỏ hàm là một đối tượng. Con trỏ tới một con trỏ hàm không chỉ "hành xử như", mà còn một con trỏ tới một đối tượng.

Tôi có thể lưu trữ nó trong void * và lấy nó từ void * bằng static_cast. Là hành vi này được đảm bảo bởi Tiêu chuẩn?

Chuyển đổi giữa con trỏ thành void và con trỏ đến đối tượng được cho phép, có. Và chuyển đổi khứ hồi được đảm bảo để mang lại con trỏ ban đầu.


Cảm ơn. Nhưng sau đó để chuyển đổi con trỏ hàm thành void * (hoặc ngược lại) tôi cần sử dụng reinterpret_cast, phải không?
Adrian

1
@Adrian Có. Tôi đã thêm một ví dụ.
eerorika

Nếu bất cứ ai muốn một ngoại lệ có lẽ: mô hình bộ nhớ trung bình dos + lớp phủ. Con trỏ chức năng lớn hơn con trỏ dữ liệu trong mô hình trung bình và lớp phủ có thể được sử dụng để đạt được bổ trợ nếu bạn cố gắng hết sức.
Joshua
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.