1

次のコードは C++ に準拠していないと聞いたことを覚えています。

std::vector<int*> intList;
intList.push_back(new int(2));
intList.push_back(new int(10));
intList.push_back(new int(17));

for(std::vector<int*>::iterator i = intList.begin(); i != intList.end(); ++i) {
  delete *i;
}
intList.clear()

その理由は、ベクトルが無効なメモリへのポインターを含むことは違法であるというものでした。明らかに、私の例はコンパイルされ、私が知っているすべてのコンパイラで動作しますが、それは標準に準拠した C++ ですか、それとも次のことを行う必要があるのでしょうか。実際には標準に準拠したアプローチであると言われました。

while(!intList.empty()) {
  int* element = intList.back();
  intList.pop_back();
  delete element;
}
4

8 に答える 8

8

コードは有効ですが、より良い解決策はスマート ポインターを使用することです。

問題は、すべての要件std::vectorが C++ 標準の 23.2.4 セクションにあることです。無効なポインターに関する制限はありません。は他の型と同様にstd::vector動作し( の場合は考慮しません)、それらがどこを指しているかは気にしません。int*vector<bool>

于 2010-06-16T18:42:28.900 に答える
5

あなたのコードは問題ありません。要素が一時的に無効になることが何らかの理由で心配な場合は、ループの本体を次のように変更します

int* tmp = 0;
swap (tmp, *i);
delete tmp;
于 2010-06-16T18:55:24.120 に答える
2

C++ の哲学は、プログラマーに可能な限り多くの自由を与え、実際に害を及ぼすものだけを禁止することです。無効なポインター自体は害を及ぼさないため、自由に使用できます。害を及ぼすのは、何らかの方法でポインターを使用することであり、したがって、未定義の動作が呼び出されます。

于 2010-06-16T19:16:03.967 に答える
1

最終的には、これは何よりも個人の好みの問題です。無効なポインターを含むベクターを使用することは「標準に準拠していない」わけではありませんが、無効なメモリを指すポインターを使用するのと同じように危険です後者の例では、ベクターに不正なポインターが含まれていないことが保証されるため、最も安全な選択です。

ただし、前の例のループ中にベクトルが使用されないことがわかっている場合 (たとえば、ベクトルがローカルにスコープされている場合) は、まったく問題ありません。

于 2010-06-16T18:42:39.003 に答える
0

ベクトルが無効なメモリへのポインタを含むことは違法です

これは、コンテナの内容について標準が述べなければならないことです。

(23.3) : これらのコンポーネントに格納されるオブジェクトの型は、CopyConstructible型 (20.1.3) の要件と、Assignable 型の追加要件を満たす必要があります

(20.1.3.1, CopyConstructible) : 次の表 30 で、T はテンプレートをインスタンス化する C++ プログラムによって提供される型であり、t は型 T の値であり、u は型 const T の値です。

expression  return type  requirement
xxxxxxxxxx    xxxxxxxxxxx  xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
T(t)                       t is equivelant to T(t)
T(u)                       u is equivelant to T(u)
t.~T()      
&t          T*           denotes the address of t
&u          const T*     denotes the address of u

(23.1.4、Assignable) : 64、T はコンテナーのインスタンス化に使用される型、t は T の値、u は (場合によっては const) T の値です。

expression  return type  requirement
xxxxxxxxxx    xxxxxxxxxxx  xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
t = u         T&           t is equivilant to u

STL コレクションの内容については以上です。ポインターについては何も述べておらず、有効なメモリを指すポインターについては特に沈黙しています。

したがって、 でdeleteポインターを ing することは、vectorおそらく非常に悪いアーキテクチャ上の決定であり、土曜日の夜の午前 3 時にデバッガーを使用して痛みと苦しみを招くことになりますが、完全に合法です。

編集:

「無効なポインター値にポインターを割り当てると、未定義の動作が発生する」という Kranar のコメントについて。いいえ、これは正しくありません。このコードは完全に有効です:

Foo* foo = new Foo();
delete foo;
Foo* foo_2 = foo;  // This is legal

foo違法なのは、そのポインター (または、さらに言えば) で何かをしようとすることです。

delete foo_2; // UB
foo_2->do_something(); // UB
Foo& foo_ref = *foo_2; // UB

ワイルド ポインターを作成するだけでも、標準に従って合法です。おそらく良い考えではありませんが、それでも合法です。

EDIT2:

ポインター型に関する標準からの詳細。

したがって、標準(3.9.2.3)は次のように述べています。

... オブジェクト ポインター型の有効な値は、メモリ内のバイトのアドレス (1.7) または null ポインター (4.10) のいずれかを表します...

...そして「メモリ内のバイト」(1.7.1)に関して:

C++ メモリ モデルの基本的な記憶単位はバイトです。1 バイトは、少なくとも基本的な実行文字セットの任意のメンバーを格納するのに十分な大きさであり、一連の連続したビットで構成されており、その数は実装によって定義されています。最下位ビットは下位ビットと呼ばれます。最上位ビットは上位ビットと呼ばれます。C++ プログラムで使用できるメモリは、1 つまたは複数の連続したバイト シーケンスで構成されます。すべてのバイトには固有のアドレスがあります。

Fooそのバイトが生活の一部であること、あなたがそれにアクセスできること、またはそのようなものについては、ここには何もありません。メモリ内の単なるバイトです。

于 2010-06-16T19:44:16.450 に答える
0

これが標準準拠の問題だとは思いません。C++ 標準では、言語の構文と実装要件が定義されています。強力なライブラリである STL を使用していますが、すべてのライブラリと同様に、C++ 自体の一部ではありません...ただし、積極的に使用すると、STL や Qt などのライブラリが言語を別のスーパーセット言語に拡張すると主張できると思います.

無効なポインターは、C++ 標準に完全に準拠しています。コンピューターは、それらを逆参照すると気に入らないだけです。

あなたが求めているのは、ベストプラクティスの質問です。コードがマルチスレッドでintList共有される可能性がある場合、最初のアプローチはより危険かもしれませんが、Greg が示唆したように、intListアクセスできないことがわかっている場合は、最初のアプローチがより効率的である可能性があります。そうは言っても、パフォーマンスの問題があることがわかるまでは、通常、安全性はトレードオフで勝つべきだと思います。

Design by Contract の概念で示唆されているように、すべてのコードは、暗黙的または明示的なコントラクトを定義します。このようなコードの本当の問題は、事前条件、事後条件、不変条件など、ユーザーに何を約束するかです。ライブラリは特定のコントラクトを作成し、作成する各関数は独自のコントラクトを定義します。コードの適切なバランスを選択するだけでよく、ユーザー (または今から 6 か月後の自分) に何が安全で何が安全でないかを明確にしていれば問題ありません。

API で文書化されたベスト プラクティスがある場合は、可能な限りそれらを使用してください。それらはおそらくベスト プラクティスであり、それには理由があります。ただし、ベスト プラクティスは見る人の目に留まる可能性があることを忘れないでください。つまり、すべての状況でベスト プラクティスとは限らないということです。

于 2010-06-16T19:31:36.443 に答える
0

生のポインターをコンテナーに格納する場合 (これはお勧めしません)、2 フェーズの削除を行う必要がある場合、2 番目のオプションよりも 1 番目のオプションを選択します。

一度に 1 つのアイテムをポップするよりも、container::clear() の方が効率的にマップのコンテンツを削除できると思います。

おそらく、for ループをナイス (疑似)forall(begin(),end(),delete)に変えて、より一般的なものにすることができるので、ベクターから他のコンテナーに変更しても問題になりません。

于 2010-06-16T19:07:17.650 に答える
0

どこで聞いた?このことを考慮:

std::vector<int *> intList(5);

5 つの無効なポインターで満たされたベクターを作成しました。

于 2010-06-16T18:44:16.760 に答える