タグ付けされた質問 「language-lawyer」

プログラミング言語と環境の正式または信頼できる仕様の複雑さについての質問。


2
Roslynに非同期ステートマシンクラス(構造体ではない)があるのはなぜですか?
この非常に単純な非同期メソッドについて考えてみましょう。 static async Task myMethodAsync() { await Task.Delay(500); } これをVS2013(Roslyn以前のコンパイラ)でコンパイルすると、生成されたステートマシンは構造体になります。 private struct <myMethodAsync>d__0 : IAsyncStateMachine { ... void IAsyncStateMachine.MoveNext() { ... } } VS2015(Roslyn)でコンパイルすると、生成されるコードは次のようになります。 private sealed class <myMethodAsync>d__1 : IAsyncStateMachine { ... void IAsyncStateMachine.MoveNext() { ... } } ご覧のとおり、Roslynはクラスを生成します(構造体ではありません)。古いコンパイラ(CTP2012だと思います)でのasync / awaitサポートの最初の実装もクラスを生成し、パフォーマンス上の理由から構造体に変更されたことを正しく覚えていれば。(場合によっては、ボクシングとヒープの割り当てを完全に回避できます…)(これを参照) Roslynでこれが再び変更された理由を誰かが知っていますか?(これに関しては問題ありません。この変更は透過的であり、コードの動作を変更しないことを知っています。興味があります) 編集: @Damien_The_Unbeliever(およびソースコード:))imhoからの回答がすべてを説明しています。説明されているRoslynの動作は、デバッグビルドにのみ適用されます(コメントに記載されているCLRの制限のために必要です)。リリースでは、構造体も生成します(そのすべての利点があります)。したがって、これは編集と続行の両方をサポートし、本番環境でのパフォーマンスを向上させるための非常に賢いソリューションのようです。興味深いもの、参加してくれたすべての人に感謝します!

2
std ::構造化バインディングを無視しますか?
前奏曲: std::tuple<int, int, int> f(); std::tuple<int, int, float, int> g(); C ++ 1zでは、構造化バインディングの構文が導入され、代わりに書き込みが可能になります。 int a, b, c; std::tie(a, b, c) = f(); 何かのようなもの auto [a, b, c] = f(); ただし、特定のコンポーネントを無視するようstd::tieに指定std::ignoreすることもできます。例: std::tie(a, b, std::ignore, c) = g(); 新しい構造化バインディング構文を使用して同様のことを行うことは可能ですか?それはどのように機能しますか?

6
C ++で参照が「const」ではないのはなぜですか?
「const変数」は、一度割り当てられると、次のように変数を変更できないことを示しています。 int const i = 1; i = 2; 上記のプログラムはコンパイルに失敗します。gccはエラーでプロンプトを出します: assignment of read-only variable 'i' 問題ありません、私はそれを理解できますが、次の例は私の理解を超えています: #include<iostream> using namespace std; int main() { boolalpha(cout); int const i = 1; cout << is_const<decltype(i)>::value << endl; int const &ri = i; cout << is_const<decltype(ri)>::value << endl; return 0; } 出力します true false …



4
未定義の動作を含むソースコードがコンパイラをクラッシュさせることは合法ですか?
未定義の振る舞いを呼び出す、不十分に記述されたC ++ソースコードをコンパイルしようとすると、(彼らが言うように)「何でも起こり得る」としましょう。 C ++言語仕様が「準拠」コンパイラで許容できると見なすものの観点から、このシナリオの「すべて」には、コンパイラのクラッシュ(またはパスワードの盗用、またはコンパイル時の誤動作やエラーアウト)が含まれますか。未定義の振る舞いの範囲は、結果の実行可能ファイルが実行されたときに何が起こり得るかに特に限定されていますか?

6
純粋関数:「副作用なし」は「同じ入力が与えられた場合、常に同じ出力」を意味しますか?
関数pureを次のように定義する2つの条件は次のとおりです。 副作用はありません(つまり、ローカルスコープへの変更のみが許可されます) 同じ入力が与えられた場合、常に同じ出力を返します 最初の条件が常に真である場合、2番目の条件が真でない場合はありますか? つまり、それは本当に最初の条件でのみ必要ですか?

3
C ++ 17以降、正しいアドレスとタイプのポインターは常に有効なポインターですか?
(この質問と回答を参照してください。) C ++ 17標準の前は、次の文が[basic.compound] / 3に含まれていました。 タイプTのオブジェクトがアドレスAにある場合、値がアドレスAであるタイプcv T *のポインターは、値の取得方法に関係なく、そのオブジェクトを指していると言われます。 しかし、C ++ 17以降、この文は削除されました。 たとえば、この文によってこのサンプルコードが定義され、C ++ 17以降は未定義の動作であると思います。 alignas(int) unsigned char buffer[2*sizeof(int)]; auto p1=new(buffer) int{}; auto p2=new(p1+1) int{}; *(p1+1)=10; C ++ 17より前p1+1は、へのアドレスを保持し*p2、正しい型を持っているので*(p1+1)、へのポインタもそうです*p2。C ++で17p1+1ある過去エンドポインタになっていないので、オブジェクトへのポインタと、私はそれがdereferencableではないと信じています。 この標準的な権利の変更の解釈ですか、それとも引用された文の削除を補償する他の規則がありますか?

2
c ++ 0xでnullptrを削除しても安全ですか?
でc++03、nullポインタを削除しても効果がないことは明らかです。確かに、それはその中で明確に述べられ§5.3.5/2ています: どちらの方法でも、deleteのオペランドの値がnullポインターの場合、操作は効果がありません。 ただし、この文の現在のドラフトではc++0x欠落しているようです。ドラフトの残りの部分では、delete-expressionのオペランドがnullポインター定数でない場合に何が起こるかを示す文しか見つかりませんでした。ヌルポインタの削除はまだで定義されてc++0xいますか?もしそうなら、どこで? ノート: それがまだ十分に定義されていることを示唆する重要な状況証拠があります。 まず、次のように§5.3.5/2述べている2つの文があります 最初の選択肢(オブジェクトの削除)では、deleteのオペランドの値はnullポインター値である可能性があります... そして 2番目の選択肢(配列の削除)では、deleteのオペランドの値はnullポインター値または... これらは、オペランドがnullであることが許可されていることを示していますが、それ自体では、nullの場合に何が起こるかを実際には定義していません。 第二に、の意味を変更することdelete 0は大きな重大な変更であり、標準化委員会がこの特定の変更を行う可能性はほとんどありません。さらに、これがc++0xドラフトの互換性アネックス(アネックスC)の重大な変更であるという言及はありません。ただし、附属書Cは有益なセクションであるため、これには規格の解釈は含まれていません。 一方、nullポインタを削除しても効果がないという事実は、追加の実行時チェックを意味します。多くのコードでは、オペランドがnullになることはないため、このランタイムチェックはオーバーヘッドゼロの原則と矛盾します。たぶん、委員会は、標準のc ++を言語の指定された設計目標にさらに一致させるために、動作を変更することを決定しました。

4
C ++でのコンマ演算子の動作が異なりますか?
これ(コンマ演算子に注意してください): #include <iostream> int main() { int x; x = 2, 3; std::cout << x << "\n"; return 0; } 出力2。 ただし、returnコンマ演算子とともに使用する場合は、次のようになります。 #include <iostream> int f() { return 2, 3; } int main() { int x; x = f(); std::cout << x << "\n"; return 0; } 出力3。 コンマ演算子の動作が異なるのはなぜreturnですか?

9
実行されないコードは未定義の動作を呼び出すことができますか?
未定義の動作(この例ではゼロ除算)を呼び出すコードは実行されませんが、プログラムはまだ未定義の動作ですか? int main(void) { int i; if(0) { i = 1/0; } return 0; } それはまだ未定義の振る舞いだと思いますが、私を支持または否定するための証拠を標準で見つけることができません。 それで、何かアイデアはありますか?

4
この構造はどのようにしてsizeof == 0を持つことができますか?
sizeofを返す構造を要求する古い投稿があり0ます。評判の高いユーザーから、標準ではタイプや変数のサイズを0にすることはできないという高得点の回答がいくつかあります。私はそれに100%同意します。 しかし、この解決策を提示するこの新しい答えがあります: struct ZeroMemory { int *a[0]; }; 反対票を投じてコメントしようとしていましたが、ここで過ごした時間は、私が100%確信していることさえチェックすることを教えてくれました。だから...驚いたことに、両方とも同じ結果gccをclang示しています:sizeof(ZeroMemory) == 0。さらに、変数のサイズは0次のとおりです。 ZeroMemory z{}; static_assert(sizeof(z) == 0); // Awkward... わぁぁぁぁぁ…? ゴッドボルトリンク これはどのように可能ですか?

4
異なるコンパイラによって呼び出される異なるキャスト演算子
次の短いC ++プログラムについて考えてみます。 #include <iostream> class B { public: operator bool() const { return false; } }; class B2 : public B { public: operator int() { return 5; } }; int main() { B2 b; std::cout << std::boolalpha << (bool)b << std::endl; } 異なるコンパイラでコンパイルすると、さまざまな結果が得られます。Clang3.4とGCC4.4.7ではtrue、を印刷しますが、Visual Studio 2013はを印刷falseし(bool)bます。つまり、で異なるキャスト演算子を呼び出します。規格による正しい動作はどれですか? 私の理解でoperator bool()は、変換は必要ありませんoperator int()が、inttobool変換が必要になるため、コンパイラーは最初のものを選択する必要があります。それでconst何かをしますか、const-conversionはコンパイラによってより「高価」であると見なされますか? を削除するとconst、すべてのコンパイラが等しくfalse出力として生成されます。一方、2つのクラスを組み合わせると(両方の演算子が同じクラスになります)、3つのコンパイラーすべてがtrue出力を生成します。

4
memcpy(0,0,0)を実行しても安全であることが保証されていますか?
私はC標準にあまり精通していないので、ご容赦ください。 規格で保証されているかどうか知りたいのですが memcpy(0,0,0)安全が。 私が見つけた唯一の制限は、メモリ領域が重複している場合、動作が定義されていないことです... しかし、ここでメモリ領域が重複していると見なすことができますか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.