“Đầu độc một hàm” trong C ++ có nghĩa là gì?


96

Vào cuối bài nói chuyện của Scott Schurr "Giới thiệu constexpr" tại CppCon , anh ấy hỏi "Có cách nào để đầu độc một chức năng" không? Sau đó, ông giải thích rằng điều này có thể được thực hiện (mặc dù theo cách không chuẩn) bằng cách:

  1. Đưa throwvào một constexprhàm
  2. Tuyên bố chưa được giải quyết extern const char*
  3. Tham khảo những điều chưa được giải quyết externtrongthrow

Tôi cảm thấy rằng tôi hơi lạc lõng ở đây, nhưng tôi tò mò:

  • "Đầu độc một hàm" nghĩa là gì?
  • Ý nghĩa / tính hữu ích của kỹ thuật mà anh ta vạch ra là gì?

1
Bạn chưa bao giờ nghe về thuật ngữ đó, vui lòng làm rõ với một ví dụ ngắn gọn!
πάντα ῥεῖ

6
@ πάνταῥεῖ, tôi chỉ làm rõ. Thuật ngữ này một 'biết đến rộng rãi trong giới nhỏ'
Sergeya

4
Anh ấy đang nói về việc đảm bảo rằng mọi lệnh gọi đến constexprhàm đều được đánh giá tại thời điểm biên dịch.
TC

@TC Right - anh ấy đã đề cập rằng một constexprhàm có thể được sử dụng tại thời điểm biên dịch hoặc thời gian chạy. Vì vậy, đây là một cách để buộc nó để bạn không thể sử dụng nó lúc chạy? Khi nào điều đó hữu ích?
sudo thực hiện cài đặt

3
Đặc biệt là trong C ++ 11, một constexprhàm thường không được triển khai hiệu quả nhất vì những ràng buộc, vì vậy người ta có thể không muốn nó được đánh giá trong thời gian chạy; hoặc, có thể đó là trường hợp lỗi (như trong ví dụ của anh ấy).
TC

Câu trả lời:


106

Nói chung, nó đề cập đến việc làm cho một hàm không sử dụng được, ví dụ nếu bạn muốn cấm sử dụng cấp phát động trong một chương trình, bạn có thể "đầu độc" mallochàm để nó không thể được sử dụng.

Trong video, anh ấy đang sử dụng nó theo một cách cụ thể hơn, điều này rõ ràng nếu bạn đọc trang trình bày được hiển thị khi anh ấy nói về việc đầu độc hàm, có nội dung "Một cách chỉ buộc thời gian biên dịch?"

Vì vậy, anh ấy đang nói về việc "đầu độc" hàm để làm cho nó không thể gọi được trong thời gian chạy, vì vậy nó chỉ có thể gọi trong các biểu thức không đổi. Kỹ thuật này là để có một nhánh trong hàm không bao giờ được sử dụng khi được gọi trong bối cảnh thời gian biên dịch và làm cho nhánh đó chứa một cái gì đó sẽ gây ra lỗi.

Một throwbiểu thức được cho phép trong một hàm constexpr, miễn là nó không bao giờ được đạt tới trong các lần gọi hàm trong thời gian biên dịch (bởi vì bạn không thể ném một ngoại lệ vào thời gian biên dịch, đó là một hoạt động động vốn có, như cấp phát bộ nhớ). Vì vậy, một biểu thức ném tham chiếu đến một ký hiệu không xác định sẽ không được sử dụng trong các lệnh gọi thời gian biên dịch (vì điều đó sẽ không thể biên dịch) và không thể được sử dụng trong thời gian chạy, vì ký hiệu không xác định gây ra lỗi trình liên kết.

Bởi vì biểu tượng không xác định không được "sử dụng odr" trong các lệnh gọi thời gian biên dịch của hàm, nên trên thực tế, trình biên dịch sẽ không tạo tham chiếu đến biểu tượng, vì vậy nó không được xác định.

Điều đó có hữu ích không? Anh ấy đang trình bày cách thực hiện, không nhất thiết phải nói rằng đó là một ý tưởng hay hoặc hữu ích rộng rãi. Nếu bạn cần làm điều đó vì lý do nào đó thì kỹ thuật của anh ấy có thể giải quyết vấn đề của bạn. Nếu bạn không có nhu cầu về nó, bạn không cần phải lo lắng về nó.

Một lý do khiến nó thể hữu ích là khi phiên bản thời gian biên dịch của một số hoạt động không hiệu quả như nó có thể. Có những hạn chế về loại biểu thức được phép trong một hàm constexpr (đặc biệt là trong C ++ 11, một số hạn chế đã được gỡ bỏ trong C ++ 14). Vì vậy, bạn có thể có hai phiên bản của một hàm để thực hiện một phép tính, một phiên bản là tối ưu, nhưng sử dụng các biểu thức không được phép trong hàm constexpr và một phiên bản là hàm constexpr hợp lệ, nhưng sẽ hoạt động kém nếu được gọi khi chạy- thời gian. Bạn có thể sử dụng phiên bản tối ưu phụ để đảm bảo nó không bao giờ được sử dụng cho các cuộc gọi thời gian chạy, đảm bảo phiên bản (không phải constexpr) hiệu quả hơn được sử dụng cho các cuộc gọi thời gian chạy.

NB Hiệu suất của một hàm constexpr được sử dụng trong thời gian biên dịch không thực sự quan trọng, vì dù sao nó cũng không có chi phí thời gian chạy. Nó có thể làm chậm quá trình biên dịch của bạn bằng cách làm cho trình biên dịch làm thêm công việc, nhưng nó sẽ không có bất kỳ chi phí hiệu suất thời gian chạy nào.


1
Tôi đã đọc nội dung của slide, nhưng tôi không thấy sự liên quan đến thuật ngữ anh ấy đang sử dụng. Rõ ràng là bây giờ bạn đã giải thích nó, nhưng tôi không thấy nó vào lúc đó. Cảm ơn rất nhiều vì câu trả lời xuất sắc này - Tôi chỉ thích trang web này.
sudo thực hiện cài đặt

@PravasiMeet, hãy đặt câu hỏi của riêng bạn, đừng chiếm đoạt nhận xét về câu hỏi của người khác về điều gì đó khác biệt. Một giải pháp đơn giản sẽ là xác định nó là đã bị xóa trong mọi đơn vị dịch, hoặc thay thế nó bằng định nghĩa của riêng bạn có tham chiếu đến một ký hiệu không xác định.
Jonathan Wakely

17

'Đầu độc' một số nhận dạng có nghĩa là bất kỳ tham chiếu nào đến số nhận dạng sau khi 'đầu độc' đều là lỗi trình biên dịch cứng. Ví dụ, kỹ thuật này có thể được sử dụng để không dùng nữa (hàm IS không được chấp nhận, đừng bao giờ sử dụng nó!).

Trong GCC truyền thống đã có một pragma cho việc này: #pragma GCC poison.


1
Có, nhưng không hoàn toàn theo nghĩa được sử dụng trong bài nói đó.
TC

@TC, ok, tôi có lẽ nên xem nó trước khi trả lời :)
SergeyA
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.