Что значит "отравить функцию" в C++?


в самом конце выступления Скотта Шурра constexpr " на CppCon, он спрашивает:"Есть ли способ отравить функцию"? Затем он объясняет, что это можно сделать (хотя и нестандартным способом):

  1. поставить throw на constexpr функции
  2. объявления нерешенных extern const char*
  3. ссылка на неразрешенный extern на throw

Я чувствую, что я немного не в своей тарелке здесь, но я любопытно:

  • что значит "отравить функцию"?
  • какова значимость / полезность техники, которую он описывает?
2 93

2 ответа:

В общем случае это относится к тому, чтобы сделать функцию непригодной для использования, например, если вы хотите запретить использование динамического распределения в программе, вы можете "отравить"malloc функция, поэтому она не может быть использована.

в видео он использует его более определенным образом, что ясно, если Вы читаете слайд, который отображается, когда он говорит об отравлении функции, в которой говорится: "способ заставить только время компиляции?"

таким образом, он говорит об "отравлении" функции, чтобы сделать ее невосстанавливаемой при время выполнения, так что это только вызывается в постоянных выражениях. Метод состоит в том, чтобы иметь ветвь в функции, которая никогда не берется при вызове в контексте времени компиляции, и чтобы эта ветвь содержала что-то, что вызовет ошибку.

A throw выражение разрешено в функции constexpr, если оно никогда не достигается во время вызова функции во время компиляции (поскольку вы не можете создать исключение во время компиляции, это по своей сути динамическая операция, как выделение памяти). Таким образом, выражение throw, которое ссылается на неопределенный символ, не будет использоваться во время вызовов времени компиляции (потому что это не удалось бы скомпилировать) и не может использоваться во время выполнения, потому что неопределенный символ вызывает ошибку компоновщика.

поскольку неопределенный символ не "используется odr" во время компиляции вызова функции, на практике компилятор не будет создавать ссылку на символ, так что это нормально, что он не определен.

это полезно? Он демонстрирует как чтобы сделать это, не обязательно говорить, что это хорошая идея или широко полезно. Если у вас есть необходимость сделать это по какой-то причине, то его техника может решить вашу проблему. Если у вас нет потребности в этом, вам не нужно беспокоиться об этом.

одна из причин может полезно, когда версия времени компиляции какой-либо операции не так эффективна, как это могло бы быть. Существуют ограничения на вид выражений, разрешенных в функции constexpr (особенно в C++11, некоторые ограничения были удалены в C++14). Таким образом, у вас может быть две версии функции для выполнения вычисления, одна из которых является оптимальной, но использует выражения, которые не разрешены в функции constexpr, и одна, которая является допустимой функцией constexpr, но будет работать плохо, если она вызывается во время выполнения. Вы можете отравить субоптимальный, чтобы он никогда не использовался для вызовов времени выполнения, гарантируя, что более эффективная (не constexpr) версия используется для времени выполнения звонки.

N. B. производительность функции constexpr, используемой во время компиляции, не очень важна, потому что у нее нет накладных расходов во время выполнения. Это может замедлить компиляцию, заставляя компилятор выполнять дополнительную работу, но у него не будет никаких затрат на производительность во время выполнения.

'отравление' идентификатор означает, что любая ссылка на идентификатор после 'отравления' является жесткой ошибкой компилятора. Этот метод может быть использован, например, для жесткого устаревания (функция устарела, никогда не используйте ее!).

в GCC традиционно была ПРАГМА для этого:#pragma GCC poison.