1. ホーム
  2. c++

[解決済み] C++で「関数に毒を盛る」とはどういう意味か?

2023-01-29 11:09:29

質問

Scott Schurr氏の講演の最後のほうで を紹介します。 constexpr CppCon での " の紹介 で、彼は「関数に毒を盛る方法はあるのか?そして、彼はこれが (非標準的な方法ではありますが) 次のようにできることを説明しています。

  1. を置く。 throw の中に constexpr 機能
  2. 未解決のものを宣言する extern const char*
  3. 未解決のものを参照する extern の中で throw

私はここで少し私の深みから外れていることを感じていますが、私は好奇心を持っています。

  • 関数に毒を盛るとはどういう意味ですか。
  • 彼が概説しているテクニックの意義や有用性は何ですか?

どのように解決するのですか?

一般的には、関数を使用不能にすることを指します。例えば、プログラムで動的割り当てを使用することを禁止したい場合、"poison" を使用することができます。 malloc 関数が使用できないようにすることです。

ビデオでは、彼はより具体的な方法でそれを使用しています。それは、彼が関数のポイズニングについて話すときに表示されるスライドを読めば明らかで、そこには "コンパイル時のみを強制する方法?" と書いてあります。

つまり、彼は関数を実行時に呼び出せないようにする "ポイズニング"について話しているわけで、それは だけです。 のみ呼び出し可能です。このテクニックは、コンパイル時のコンテキストで呼び出されたときには決して実行されない関数の分岐を用意し、その分岐にエラーを引き起こす何かを含ませることです。

A throw 式は、コンパイル時にその関数に到達しない限り、constexpr 関数内で使用することができます(コンパイル時に例外を投げることはできないので、メモリの割り当てと同様に本質的に動的な操作です)。つまり、未定義のシンボルを参照する throw 式は、コンパイル時の呼び出しでは使用されず(コンパイルに失敗するため)、実行時には使用できません(未定義のシンボルはリンカーエラーを引き起こすため)。

未定義のシンボルは関数のコンパイル時の呼び出しでは "odor-used"されないので、実際にはコンパイラはそのシンボルへの参照を作成しないので、未定義であっても問題ないのですが、そのシンボルはコンパイル時の呼び出しでは使用されないので、実行時には使用できません。

これって役に立つの?彼がデモしているのは どのように を実演しているのであって、必ずしもそれが良いアイデアであるとか、広く有用であると言っているわけではありません。もし、あなたが何らかの理由でそれをする必要があるのなら、彼の技術はあなたの問題を解決してくれるかもしれません。その必要がないのであれば、気にする必要はないでしょう。

一つの理由は、それが かもしれない が有用である理由の 1 つは、ある操作のコンパイル時バージョンが効率的でない場合です。constexpr 関数で許可される式の種類には制限があります(特に C++11 では、一部の制限が C++14 で削除されました)。つまり、ある計算を行うための関数に、最適だが constexpr 関数で許可されていない式を使ったものと、有効な constexpr 関数だが実行時に呼び出されるとパフォーマンスが低下するものの2つのバージョンがある可能性があります。最適ではない方の関数が実行時の呼び出しに決して使われないように毒殺し、より効率的な(constexprでない)バージョンが実行時の呼び出しに使われるようにすることができます。

N.B. コンパイル時に使用されるconstexpr関数の性能は、実行時のオーバーヘッドがないため、あまり重要ではありません。コンパイラに余分な仕事をさせることでコンパイルを遅くするかもしれませんが、実行時性能のコストは発生しないでしょう。