質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.39%
C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

486閲覧

配列の最後の要素をひとつ超えた場所

SaitoAtsushi

総合スコア5604

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

3クリップ

投稿2024/09/08 05:37

この質問で言う C とは C99 のこと、 C++ は C++11 のことという前提を置きます。

以下のような配列をポインタで辿るプログラムがあったとして、 &foo[3] の部分は C++ として未規定ではないと考えてよいですか?

cpp

1#include <stdio.h> 2 3int main(void) { 4 int foo[3] = {1, 2, 3}; 5 for(int* p=foo; p<&foo[3]; ++p) { 6 printf("%d", *p); 7 } 8}

私の思考過程をたどる形で質問をもう少し詳細にします。

C では

  • E1[E2](*((E1)+(E2))) と等価である
  • ポインタと整数の加算の結果は配列の要素か配列の最後の要素をひとつ超えたところを指さなければならない (そうでなければ未定義)
  • ポインタと整数の加算の結果が配列の最後の要素をひとつ超えたところを指す場合、評価される単項 * 演算子のオペランドとしてはならない
  • 単項 & のオペランドが単項 * の結果である場合は &* も評価しない (両者を取り除いた場合と同じ結果)

という規則によって &foo[3]foo+3 と同じ結果となり、配列の最後の要素をひとつ越えた場所を指すポインタが生成されるけれどもそこにアクセスはしないので未定義を踏んでいないと考えられます。

しかし C++ では &* を相殺する規則が存在しません。 そのかわりに

という規則があり、単項 & のオペランドが単項 * の結果であった場合には結果的にこの変換が起こらないのでオブジェクトが初期化されているかどうかが問題にされるパスを通らず未定義にはあたらないと思います。

この理解で正しいでしょうか? というのが質問の意図です。

C++11 より後の規格でも事情が大きく変わっているところはないと思いますが、もしも特に知る必要がある改定があるならば補足いただけるとありがたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2024/09/08 15:12

C++の規格書は見てませんが、 > glvalue から prvalue への変換時にオブジェクトが初期化されていない場合の動作は未定義 の記述だけを見ると、これは、X を変数とすると、右辺値を書くところに X と書くと変数から値が取り出される場合のことについて書いてあるように見えます。 (配列でない)変数の変数名は、元々左辺値で、右辺値が要求されるところに書くと自動的にデリファレンスされると理解しています。C/C++の用語として正しいかどうかは分かりませんが。一般論として。 1の部分は、Xの型と関係ない型にキャストしたり、Xに生成したオブジェクトを代入していない状態で値を取り出すと未定義という事など。 2の部分は、&& || ? : などの演算子のオペランドだと評価されないこともあり得て、その場合は値が取り出されないなど。 (左辺値になり得る)変数相当に演算子&を付けることで、右辺値であるアドレスに変わるということとは関係ないのではないでしょうか? 全体の中でのこの節の位置づけが把握できてないので、的外れかも知れませんが。
SaitoAtsushi

2024/09/08 19:53

関係ないです。 この場合は左辺値のままのはずなので未定義を引き起こしうる操作 (右辺値への変換) と関係しませんから大丈夫ですよね? という意味です。
otn

2024/09/09 12:40

> この場合は左辺値のままのはずなので C++11では &foo[3] は左辺値と言うことしたか。Cだと右辺値なので、同じかと思っていました。 私のコメントは、&foo[3] が右辺値であるのが前提です。失礼しました。 そうすると、「左辺値から左辺値への変換だけど、途中で一旦右辺値を経由することは無いですよね?」という質問になりますか?そうだとすると、「実装としては無いだろう」とは言えると思いますが、規格でその旨が保証されてるか知りたいというのが質問ポイントですかね。
SaitoAtsushi

2024/09/09 12:56

いえ、 &foo[3] は右辺値です。 & は「左辺値を (左辺値のまま) オペランドとして受け取ってそのアドレス (prvalue) を返す」であって「左辺値を右辺値に暗黙に変換する (prvalue を返す)」という工程を経ませんということを述べてます。
utm.

2024/09/09 12:56

E1[E2] は (*((E1)+(E2))) と等価であるというのがC++でも同じであるなら、 (&foo[2]+1)と&foo[3]は等価なはずなので、 foo[3]が評価されるというのはおかしいでしょうから、そちらの方面で調べてみてはいかがでしょうか。 この定義は再帰的に表現出来ますので、&foo[3]が未定義動作ならここを参照する術が物理的に無くなる気もします。 質問の趣旨としてはfoo[3]が*(foo+3)と同等なので、&*(foo+3)がいいのか?という話ですよね? このコメントがただの質問の繰り返しであればすみませんm(_ _)m
otn

2024/09/09 16:22

なるほど。 「デリファレンスをしない」を「左辺値のまま」と表現したのですね。結果は右辺値ですが。 それはちょっと予想外でした。てっきり前提間違いの指摘かと思いました。 そうすると、私がコメントで書いた、 「glvalue から prvalue への変換時にオブジェクトが初期化されていない場合の動作は未定義」の英文は、左辺値を右辺値の場所に書くと自動的にデリファレンスされるという場合だけのことを言っているのであって、演算子による変換は関係ないのでは? と言うことじゃないでしょうか?この文の範囲内ではそうとは明記されていませんが、デリファレンスについての記述だと思って読むと納得性のある説明文です。 「オペランドが左辺値限定で、デリファレンスを伴わないで、結果が右辺値」という単項演算子は他には無いか。。。
guest

回答2

0

ベストアンサー

今はcwg2823がでてきてそのあたりはみなUBになっちゃったけど、C++11の時点では、cwg232とかでもUBにしたくないなーみたいな雰囲気はありますね(決定まではない)。似たようなものとしてはcwg315(nullポインタ経由のstaticなメンバ関数呼び出しが2003年should be allowedから2024年has undefined behaviorになった件)とか。
今のexpr.unary.opだと、the operator yields an lvalue of type T. if the operand points to an object…;otherwise, the behavior is undefined…に引っかかるわけですが。

投稿2024/09/10 03:27

matukeso

総合スコア1666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

この理解で正しいでしょうか? というのが質問の意図です。

残念ながら、ポインタの値は未定義ではないですが、
それを参照した場合の、「動作は」未定義、ってことです。

投稿2024/09/08 07:10

y_waiwai

総合スコア87981

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SaitoAtsushi

2024/09/08 08:04

dereference が未定義なのはわかってます。 dereference が起こらないという話をしています。
y_waiwai

2024/09/08 09:58

ポインタ 範囲外、でググってみるとそこら辺の解説がたくさん出てきますね #逆参照が起こらない、と定義されてませんがなってはなしですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問