C ++ 20までのint未定義の動作にmallocを使用しています


96

次のコードはC ++ 20まで未定義の動作をしていると言われました。

int *p = (int*)malloc(sizeof(int));
*p = 10;

本当?

引数は、intオブジェクトに値を割り当てる前にオブジェクトの存続期間が開始されないというものでした(P0593R6)。問題を解決するには、配置newを使用する必要があります。

int *p = (int*)malloc(sizeof(int));
new (p) int;
*p = 10;

オブジェクトの存続期間を開始するために、簡単なデフォルトのコンストラクターを呼び出す必要が本当にありますか?

同時に、コードは純粋なCで未定義の動作をしません。しかし、intCコードでを割り当て、それをC ++コードで使用するとどうなりますか?

// C source code:
int *alloc_int(void)
{
    int *p = (int*)malloc(sizeof(int));
    *p = 10;
    return p;
}

// C++ source code:
extern "C" int *alloc_int(void);

auto p = alloc_int();
*p = 20;

それはまだ未定義の振る舞いですか?


8
のためにint?いいえstd::string。はい。
Eljay

8
@Eljay For int、またそうです。そうしなくても、実際には問題が発生しないというだけです。の場合std::string、それは明らかに問題を引き起こします。
バリー

C ++ 20より前では、新しいプレースメントを追加できます。そうすれば、それは整形式になり、おそらく何の費用もかかりません。
フランソワアンドリュー

8
これを変更するC ++ 20の新しいルールは何ですか?
ケビン

4
そうではないint *p = (int*)malloc(sizeof(int)); p = new(p) int;ですか?新しい配置の結果を割り当てないと、致命的な影響も生じる可能性があることに気づきました(少しばかげているように見えるかもしれませんが)。
シェフ

回答:


62

それは本当ですか?

はい。技術的に言えば、次の部分はありません。

int *p = (int*)malloc(sizeof(int));

実際には型のオブジェクトを作成するintのでp、実際intには存在しないため、逆参照はUBです。

オブジェクトの存続期間を開始するために、簡単なデフォルトのコンストラクターを呼び出す必要が本当にありますか?

C ++ 20より前の未定義の動作を回避するために、C ++オブジェクトモデルごとに行う必要がありますか?はい。これを行わないと、コンパイラは実際に害を及ぼしますか?私が知っていることではありません。

[...]それはまだ未定義の振る舞いですか?

はい。C ++ 20より前では、まだ実際にintはどこにもオブジェクトを作成していなかったので、これはUBです。


コメントは詳細な議論のためのものではありません。この会話はチャットに移動さました
Makyen

timsong-cpp.github.io/cppwp/n3337/basic.life#1.1の言語が、UBにならないのに十分でないのはなぜですか?結局のところ、intこの例では、適切なサイズと配置のストレージが取得されましたint。オブジェクトの存続期間はそこから始まります。
avakar

41

はい、UBでした。int缶が存在できる方法のリストが列挙されており、mallocが因果関係があると考えない限り、そこには適用されません。

これは標準の欠陥と広く見なされていましたが、UBの特定のビットを中心にC ++コンパイラによって行われた最適化はそのユースケースで問題を引き起こさなかったため、重要性は低くなりました。

2番目の質問に関しては、C ++はC ++とCがどのように相互作用するかを義務付けていません。したがって、Cとのすべての相互作用は... UB、別名C ++標準で定義されていない動作です。


5
intが存在する方法の列挙リストを拡張できますか?プリミティブ型の寿命について同様の質問をしたことを覚えています。仕様に別の方法が記載されていないため、プリミティブは存在すると言うだけで「存在」できると言われました。スペックの便利なセクションを見逃したようです!どのセクションを熟読すべきか知りたいです!
コートアンモン

7
@CortAmmon(任意のタイプの)オブジェクトがC ++ 20に存在する方法の列挙リストは、[intro.object]にあります:(1)定義による(2)新しい式による(3)新しいルールに従って暗黙的にP0593(4)で、ユニオンのアクティブメンバーを一時的に変更します(5)。(3)C ++ 20の新機能、(4)C ++ 17の新機能。
バリー

3
C / C ++の相互作用は本当にUBですか?未定義ではなく、実装定義である方が理にかなっています。そうでなければ、extern "C"構文がまったくないのは奇妙なことです。
ルスラン

4
@Ruslan:実装は、ISO C ++が未定義のままにする動作を自由に定義できます。(たとえばgcc -fno-strict-aliasing、またはデフォルトでMSVC)。「実装が定義されている」と言うとすべてのC ++実装は、C実装と相互運用する方法を定義する必要があるため、そのようなことを行うかどうかにかかわらず、実装に完全に任せるのは理にかなっています。
PeterCordes20年

4
@PeterCordes:なぜ多くの人がIDBとUBの違いを認識できず、すべての実装が構成を処理することを標準が義務付けていないことは、実装がそうすることを期待されるべきではないという判断を意味するという空想的な概念を採用しているのだろうか、そして、そうしない実装は、結果として劣っていると見なされてはなりません。
スーパーキャット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.