Bestiary C ++。 謎のキャラクターリファレンス







C ++では、落とし穴、トラップ、予約、およびトラップが豊富です。 C ++ダンジョンは、多くの不審なキャラクターを隠します。 ハロウィーンは、この多数のモンスターの代表者と出会うのにふさわしい時期です。









Vileタイプ





型システムには、コンパイラの作成者以外にはほとんど知られていない暗いコーナーがあります...

アリステア・メレディス 忌まわしい機能の種類

関数の忌まわしい型は、 cv-ref修飾子の後に関数の型を書くことによって得られる型です。







using abominable = void() const volatile &&;
      
      





abominable



は、ポインタはなく 、関数型の名前あり、綴られていますが、 const



でも修飾型volatile



でもありません。 型システムにはcvで修飾された関数型はなく、厄介な関数型はまったく異なるものです。







厄介な型を持つ関数を作成することは不可能です!







「私が知っているこれらのタイプの明示的なつづりの例は、コンパイラの秘密の特徴を知っていることを話し、複雑なプログラミングの競争で勝ちます。 これらのシナリオ以外では、実際のプロジェクトでそのようなイディオムを見たことはありません」


 struct rectangle { using int_property = int() const; // common signature for several methods int_property top, left, bottom, right, width, height; // declare property methods! // ... ^^^^^^^ };
      
      





怖い? 興味がありますか? テイルズオブジアボミナブル関数タイプの詳細!

ムワハハハハ...







エイリアン





ビショップ:いいえ、ケーブル接続が破損しています。 プレートを指示することはできません。

リプリー:誰かが出かけ、携帯端末を手に取り、手動で接続する必要があります。

エイリアン、1986

私はこのしゃれを許してくれますが、私はalignas



(あなたが強い斜視を持っているなら、 aliens



ようにそれを読むことができます)と彼の家族について話しています。 キーワード alignas keyword specifier



、C ++ 11で導入されました。 型またはオブジェクトの配置要件を定義します。







オブジェクトの各タイプには、「アライメント要件」と呼ばれるプロパティがあります。 これは整数値( std::size_t



型で、常に2の累乗)であり、この型のオブジェクトをメモリに配置できる連続したアドレス間のバイト数に等しくなります。 alignof



またはstd::alignment_of



を使用して、アライメント要件を要求できます。 バッファ内でポインタを正しい方法で整列させるには、ポインタ整列関数std::align



使用できますstd::aligned_storage



は、ストレージを正しい方法で整列させるのに役立ちます。 どのタイプのオブジェクトも、このタイプの各オブジェクトに位置合わせの要件を課します。 alignas



を使用すると、より厳密に整列できます(サイズ要件が大きくなります)。 非静的クラスメンバーのすべての位置合わせ要件に準拠するために、インデントを一部のメンバーの後に挿入できます。







悪魔





許容される未定義の動作は、予測できない状況を完全に無視することから、鼻から飛び出す悪魔にまで及びます。

ジョン・F・ウッズ、 コンプ。 標準 c 1992

不定の行動は、おそらく最も悪名高い鼻の悪魔の1つです。 これは言語Cに由来するため、このガイドでは他の多くのモンスターに先行しています。 不確実な行動は依然として本当の脅威であり、疑うことを知らない旅人にとっては恐怖です。 つまり、言語の特定のルールに違反すると、この動作によりプログラム全体が役に立たなくなります。







未定義の動作について多くのことが書かれています。 たとえば、John Regerによる優れた出版物( 1、2 )。 また、彼のスピーチのいくつかの録音を見てください( 1、2 )。







驚くべき新しい叙事詩: 2017年9月、悪魔はフラスコに火薬がまだあることを示しました。 この短いコードスニペットはワイルドになりました







 #include <cstdlib> // for system() typedef int (*Function)(); // typedef function pointer type static Function Do; // define function pointer, default initialized to 0 static int EraseAll() { return system("rm -rf /"); } // naughty function void NeverCalled() { Do = EraseAll; } // this function is never called! int main() { return Do(); } // call default-initialized function=UB: chaos ensues.
      
      





Clangはそれを以下にコンパイルします:







 main: movl $.L.str, %edi jmp system .L.str: .asciz "rm -rf /"
      
      





ソースコードにはEraseAll()



呼び出しはありませんが、コンパイルされたプログラムはrm -rf /



実行します! ただし、関数ポインターDo



は静的変数であり、 0



に初期化され、 0



を呼び出すと未定義の動作が発生するため、Clangではこれを行うことができます。 コンパイラがまさにそのようなコードを生成するのは奇妙に思えるかもしれませんが、実際には、これはコンパイラがプログラムを分析する方法の結果にすぎません...







この神秘的な物語の詳細については、 こちらをご覧ください







DLL地獄





これ以上ひどい悲惨さはありません

良い時代を思い出す方法

不運で。

ダンテ・アリギエーリ、神曲、地獄

DLL-hellという用語は、Windowsファミリのオペレーティングシステムで使用されるDLLを操作するときに発生する問題を表します。







DLL地獄は、アプリケーションが起動しない、または正しく動作しない場合に、さまざまな形で現れます。 Hell Dante Alighieriのサークルのように、DLL ヘルは、Windowsエコシステムの特徴である依存性 ヘルの一種です。







ダックタイピング





それがカモのように見え、カモのように鳴るが、バッテリーを必要とする場合、あなたの抽象化はおそらく間違っています。

リスコフ代替原理に関するインターネット

アヒルのタイピングは、タイプセーフティでのアヒルテストの使用です。 アヒルテスト formの一種です。







誘ductionの一般的な表現は次のとおりです。







それがカモのように見え、カモのように泳ぎ、カモのように鳴くなら、それはおそらくカモです。







「古典的な」カモタイピングでは、型チェックを実行時まで遅らせる必要があり、ほとんどの場合カモタイピングは動的に型付けされた言語を参照します(C ++とは異なります)。 ただし、ダックテストは、 静的型付けのコンテキストで、テンプレート、汎用関数、またはメソッドで使用されます。







実際、 C ++の概念を適用する主な目標の1つは、テンプレートタイプ仕様のより統制のとれた定義です。







とても静かに振る舞います...アヒルのタイピングシーズンが来ました。









アヒルのタイピングに対する概念







詳細はこちら







UFO





未知のオブジェクトは、衆生によって制御されています...

UFOがどこから来たのか、そしてその意図は何かを知ることは不可欠です...

1960年、CIA初代所長、ヒレンコッター提督

C ++ 20は、新しい演算子の言語への侵入に直面する可能性があります。







宇宙船オペレーター<=>!







<=>



は、単一の3者間比較演算子です。 定義されている場合、コンパイラは、他のすべての比較演算子<



<=



==



!=



>=



>



を自動的に生成できます。 一貫性のあるインターフェイスを提供し、半順序およびその他の機能をサポートします。







Walter E. Brown CppCon 2017でこのオペレーターについて話し 、提案P0515R2を紹介しました







悪魔





あるべきものと混同しやすいものは何ですか。 特に最初のものがあなたにとって有益な場合。

タイリオンラニスター(ベス)

C ++標準では、「 不定の振る舞い 」デーモンの危険性が低い2つの兄弟、すなわち「 悪意のない振る舞い」と「 実装定義の振る舞い 」が言及されています







実装依存の動作は、選択プロセスが実装によって文書化される不特定の動作です。 つまり、何が起こるかを正確に文書化/保証するには、実装が必要です 。 また、不特定の動作により、ドキュメント化はドキュメント化や保証を必要としません







悪魔はさまざまな装いで登場します- これは既知の悪魔の印象的な(気分を害するものではないにしても)リストです







敢えて読んでください!







非表示の変数





孤立した敵だけが非常線に侵入できます。 中に入ると、彼は見えなくなり、強く突然の打撃を与えなければなりません。 このタスクを選択しました。

シャドウ、 シャドウマガジン#131 1937

変数のシャドーイングは、あるスコープ(たとえば、ブロックまたは関数)で宣言された変数が、外側のスコープで定義された別の変数と同じ名前を持つ場合に発生します。 その後、外部変数は内部変数によって隠されます。 内部識別子は外部をマスクすると言われています。 混乱が発生する可能性があります。これは、非表示変数の名前の後続の使用が参照する変数が常に明確ではないためです。これは、言語の名前を解決する規則によって異なります。 各スコープで、同じ名前または識別子が完全に異なるタイプの異なる変数を参照できます。







変数の非表示は、C ++のみに限定されるものではありません。







鮮やかな







 bool x = true; // x is a bool auto f(float x = 5.f) { // x is a float for (int x = 0; x < 1; ++x) { // x is an int [x = std::string{"Boo!"}](){ // x is a std::string { auto [x,_] = std::make_pair(42ul, nullptr);} // x is now unsigned long }(); } }
      
      





ターミネーター





ハスタ・ラ・ビスタ、ベイビー!

ターミネーター

C ++には、通常または予期せずにプログラムを中断する驚くほど多くの方法があります。







堅牢なプログラムとライブラリを作成する場合、実行を突然中断するさまざまな方法を念頭に置くことが重要です。 さらに、これらの条件の多くは、DLLなどのモジュールにアクセスするときに発生する可能性があります。







C ++プログラムの標準ターミネーターの中には、多数の種類のstd::exit()



std::abort()



std::terminate()



std::signal()



およびstd::raise()



ます。







私はブレーカーに関する私の投稿でそれらのいくつかについて書きました。







透明なオブジェクト





男ではなく、あるもの。 子、またはstd::less<>



黒く不定形なもの。


ラルフ・エリソン、見えない男

透明な関数オブジェクトはC ++ 14に登場しました。任意の型の引数を取り、それらを完全にリダイレクトするため、異種コンテキストまたは右辺値引数で関数オブジェクトを使用する場合、コピーや変換を行う必要はありません。 たとえば、 std::set::find



およびstd::set::lower_bound



などのテンプレート関数は、比較タイプでこの要素タイプを使用します。







重要な透過関数オブジェクトには、 std::less<>



およびstd::equal_to<>



ます。







ユニコーン





良いニュースです! C ++でUnicorn Call Syntax構文を実装しました!

JF Bastien、Twitter、2016

ユニファイドコール構文の提案では、 f(x,y)



欠落している場合にf(x,y)



メンバー関数xf(y)



呼び出すことができるという考えを説明しています。 xf(y)



からf(x,y)



への逆変換は提案されていません。







統一された呼び出し構文が提案された理由「標準ライブラリの多くの型が、たとえばbegin(x)



およびx.begin()



swap(x,y)



およびx.swap(y)



2つの関数によってサポートされる状況に既に遭遇しました。 。
そして問題はさらに複雑になります。 演算子に対して解決されました。式a+b



は、スタンドアロンoperator(X,X)



関数またはコンポーネント関数X::operator(X)



を使用して解決できます。
セットのfor



begin(X)



X::begin()



両方が見つかるように問題が解決されました。
2つの特殊なケースと多くの重複した機能に対するソリューションの存在は、一般的なソリューションの必要性を示しています。 2つの表記法にはそれぞれ利点があります(たとえば、非メンバーの場合はオープンなオーバーロードセットを開き、メンバーの場合はメンバーアクセスを開きます)。 しかし、なぜユーザーはライブラリが提供する構文を知る必要があるのでしょうか?」







ユニファイドコール構文が古いコードでどのように機能するかについてはさらに多くの質問があり、UCSはまだC ++で実装されていません。







しかし、 Unicorn Call Syntaxは最も退屈なコードベース明るくします。







 struct { (int _) : _(_) {} operator int() { return _; } int _; }; operator ""_(unsigned long long _) { return _; } int main() { auto unicorn = 42_; return unicorn; }
      
      





ヴォルデモートの種類





オブジェクトに触れることなく移動できます。

ロード・ヴォルデモート、別名ザット・フー・カン・ノット・コール、「ハリー・ポッター」

Voldemort型は、その型が宣言されたスコープ外で直接名前を付けることはできませんが、外部コードはこの型を使用できます。







ヴォルデモート型は、D言語に外観あり、C ++では同じように機能します。 ここで実際にこれらのタイプを参照してください。 ウォルターブライトもそれらについて書いています。







以下の例では、 Voldemort



createVoldemortType()



内のローカル型であり、 auto



は呼び出し元にVoldemort



インスタンスを返すラムダを返します。 main()



内でVoldemort



に名前を付けることはできませんが、このタイプの変数を他のように使用できます。







 int main() { auto createVoldemortType = [] // use lambda auto return type { struct Voldemort // localy defined type { int getValue() { return 21; } }; return Voldemort{}; // return unnameable type }; auto unnameable = createVoldemortType(); // must use auto! decltype(unnameable) unnameable2; // but, can be used with decltype return unnameable.getValue() + // can use unnameable API unnameable2.getValue(); // returns 42 }
      
      





Volan de Mort型は、「factory」などの操作の匿名OOP型の 「eg食」バージョンとして使用される場合があります。 これは、ポインターとメモリー内の動的割り振りのないスタック多態性です。







 struct IFoo // abstract interface { virtual int getValue() = 0; }; inline auto bar(IFoo& foo) { return foo.getValue(); } // calls virtual interface method int main() { auto fooFactory = [] { struct VoldeFoo: IFoo // local Voldemort type derived from IFoo { int getValue() override { return 42; } }; return VoldeFoo{}; }; auto foo = fooFactory(); return bar(foo); // works as expected, returns 42. }
      
      





ゾンビ





C ++標準にはゾンビがいます。

人々には2つのタイプがあります:慎重に定義されたゾンビを持つことに何の問題もないと信じる人もいれば、ゾンビを殺す方が良いと考える人もいます。

イェンス・ウェラー。 C ++とゾンビ

移動したスコープ内のオブジェクトはどうなりますか?







破壊的な移動(現在C ++ではサポートされていません)がない場合、残りの殻オブジェクトの状態はゾンビに似ています。







「移動コンストラクターと代入演算子を実装するときは、移動だけでなく、その結果として残っているものにも注意する必要があります。 それ以外の場合、ゾンビを作成できます。その値(つまり、生命)がどこかに移動したオブジェクトです。







Eric Nieblerのマニュアルでは、オブジェクトを「最小限に意識した状態」のままにすることを強くお勧めします。「 移動したオブジェクトは、適切ではあるが指定されていない状態でなければなりません 。」 一方、ショーン・ペアレントは破壊的な移動を主張しています。







ゾンビはstd::decay



とはほとんど関係ありません。







ゾンビと脳





脳:彼らがあなたから食べたいもの[ゾンビ名]。

リチャード・スミス、 聖なるISO C ++標準インデックス

さて、子供たち、本当に怖がる準備はできていますか?







20.5.4.3.1「ゾンビ名」の Holy ISO C ++標準を開きます。







それは言います:







頭脳 :食べたいもの[名前。ゾンビ]」と「 生きている死者 、いわゆる[名前。ゾンビ]」







(私は冗談ではありません-この投稿から誰が何を期待しても!)







私たちは、以前に標準化され、後に廃止されたstd



名が安らかにstd



聖標準の地下室に入りました。 尊敬されている死者の中には、 auto_ptr



binary_function



bind1st



bind2nd



random_shuffle



unary_function



unexpected



およびunexpected_handler



ます。







ただし、これらの老朽化した住民の1つがいつレガシーコードに突然現れるかは予測できません。







おわりに



C ++は、不気味なハロウィーンのアイデアのインスピレーションの真の源です! しかし、このガイドは完全にはほど遠いものと確信しています。 C ++の奥深くで誰かを見逃した場合は、Twitter、Reddit、またはC ++ Slackチャンネルで教えてください。








All Articles