4

以下は、シーケンス ポイント ルールが原因で未定義の動作が発生する 2 つの一般的な問題です。

a[i] = i++; //has a read and write between sequence points
i = i++;   //2 writes between sequence points

シーケンスポイントに関して他に遭遇したことは何ですか?

コンパイラが警告できない場合、これらの問題を見つけるのは非常に困難です。

4

6 に答える 6

10

ダリオの例のバリエーションは次のとおりです。

void Foo(shared_ptr<Bar> a, shared_ptr<Bar> b){ ... }

int main() {
  Foo(shared_ptr<Bar>(new Bar), shared_ptr<Bar>(new Bar));
}

メモリリークする可能性があります。2 つのパラメータの評価の間にシーケンス ポイントがないため、2 番目の引数が最初の引数の前に評価されるだけでなく、両方の Bar オブジェクトがいずれかの前に作成される場合もありますshared_ptr

つまり、次のように評価されるのではなく、

Bar* b0 = new Bar();
arg0 = shared_ptr<Bar>(b0);
Bar* b1 = new Bar();
arg1 = shared_ptr<Bar>(b1);
Foo(arg0, arg1);

b0(正常に割り当てられた場合、すぐにラップされるため、安全ですshared_ptr)、次のように評価される場合があります。

Bar* b0 = new Bar();
Bar* b1 = new Bar();
arg0 = shared_ptr<Bar>(b0);
arg1 = shared_ptr<Bar>(b1);
Foo(arg0, arg1);

つまり、b0正常に割り当てられb1て例外がスローされた場合、b0削除されることはありません。

于 2009-05-13T18:21:19.647 に答える
6

パラメータリストまたは追加などの実行順序に関して、あいまいなケースがいくつかあります。

#include <iostream>

using namespace std;

int a() {
    cout << "Eval a" << endl;
    return 1;
}

int b() { 
    cout << "Eval b" << endl;
    return 2;
}

int plus(int x, int y) {
    return x + y;
}

int main() {

    int x = a() + b();
    int res = plus(a(), b());

    return 0;
}

a() または b() が最初に実行されますか? ;-)

于 2009-05-13T18:09:47.027 に答える
3

これは、BjarneStroustupによるc++を使用したプログラミングの原則と実践からの簡単なルールです。

「式の変数の値を変更した場合。同じ式で2回読み取りまたは書き込みを行わないでください。」

a[i] = i++; //i's value is changed once but read twice
i = i++;   //i's value is changed once but written twice
于 2009-05-14T16:56:56.130 に答える
1

私が最近見たものは、クラスのフォーマット時間を節約したいというプログラマーの願望によるもので、完全に間違っていました。


class A
{
public:

    ...

    const char* Format( const string& f ) const
    {
        fmt = Print( f, value );
        return fmt.c_str();
    }

    operator const char* () const { return fmt.c_str(); }

private:

    struct timeval value;
    mutable string fmt;
};

A a( ... );
printf( "%s %s\n", a.Format( x ), a.Format( y );

最後の行は、両方の形式で常に同じ値を出力します (または、内部文字列が返されたメモリを解放するため、プログラムをクラッシュさせます)。

もう1つは、私がずっと前に行ったインタビューからのものです。


void func( int x, int y, int z )
{
    printf( "%d %d %d\n", x, y, z );
}

...
int i = 0;
func( i, ++i, i++ ); /* don't do this in real software :) */

于 2009-05-14T18:30:34.393 に答える
1

人々が陥るのを見たダリオの例に似た例:

printf("%s %s\n", inet_ntoa(&addr1), inet_ntoa(&addr2));

addr1 addr1これは " " または " "を出力するだけでなくaddr2 addr2(inet_ntoa以降の呼び出しによって上書きされる静的バッファーへのポインターを返すため)、どちらが該当するかは定義されていません (C は引数で評価の順序を指定しないため)。リスト)。

于 2009-05-13T18:47:19.197 に答える
1

ほとんどの C コンパイラで機能するが、シーケンス ポイントが原因であいまいな 2 つの適切な式を次に示します。

x ^= y ^= x ^= y; // in-place swap of two variables

また、

int i=0;
printf("%d %d %d", ++i, ++i, ++i);  // usually prints out 3 2 1... but not for all compilers!
于 2009-05-14T17:37:51.977 に答える