0

std::vector で poll() を使用しました。リッスンソケットを登録しました。

std::vector<struct pollfd> fds;
fds.push_back(server_sock);

新しいクライアントソケットまたは接続されたクライアントセッションを追加して、何かをします。

// poll() ...
for(std::vector<struct pollfd>::reverse_iterator it = fds.rbegin(); it != fds.rend(); it++) {
    if (it->fd == server_sock) {
        struct pollfd newFd;
        newFd.fd = newClient;
        newFd.events = POLLIN;
        fds.push_back(newFd);
    } else {
        // do something.
    }
}

ただし、1 または 2 または 4 のベクトルの要素がある場合、reverse_iterator は正しく機能しません。なぜこれが機能するのかわかりません。

添付のサンプルコード。

typedef struct tt_a {
    int a;
    short b;
    short c;
} t_a;

vector<t_a> vec;
for (int i = 0; i < 1; i++) {
    t_a t;
    t.a = i;
    t.b = i;
    t.c = i;
    vec.push_back(t);
}

for(vector<t_a>::reverse_iterator it = vec.rbegin(); it != vec.rend(); it++) {
    if (it->a == 0) {
        t_a t;
        t.a = 13;
        t.b = 13;
        t.c = 13;
        vec.push_back(t);
    }

    printf("[&(*it):0x%08X][it->a:%d][&(*vec.rend()):0x%08X]\n",
            &(*it), it->a, &(*vec.rend()));
}

printf("---------------------------------------------\n");

for(vector<t_a>::reverse_iterator it = vec.rbegin(); it != vec.rend(); ++it) {
    if (it->a == 3) {
        it->a = 33;
        it->b = 33;
        it->c = 33;
    }
    printf("[&(*it):0x%08X][it->a:%d][&(*vec.rend()):0x%08X]\n",
            &(*it), it->a, &(*vec.rend()));
}

結果:

[&(*it):0x01ADC010][it->a:0][&(*vec.rend()):0x01ADC028]
[&(*it):0x01ADC008][it->a:33][&(*vec.rend()):0x01ADC028]
[&(*it):0x01ADC000][it->a:0][&(*vec.rend()):0x01ADC048]

ベクトルが 5 つの要素を持っている場合、正常に動作します。

[&(*it):0x007620A0][it->a:4][&(*vec.rend()):0x00762078]
[&(*it):0x00762098][it->a:3][&(*vec.rend()):0x00762078]
[&(*it):0x00762090][it->a:2][&(*vec.rend()):0x00762078]
[&(*it):0x00762088][it->a:1][&(*vec.rend()):0x00762078]
[&(*it):0x00762080][it->a:0][&(*vec.rend()):0x00762078]
---------------------------------------------
[&(*it):0x007620A8][it->a:13][&(*vec.rend()):0x00762078]
[&(*it):0x007620A0][it->a:4][&(*vec.rend()):0x00762078]
[&(*it):0x00762098][it->a:33][&(*vec.rend()):0x00762078]
[&(*it):0x00762090][it->a:2][&(*vec.rend()):0x00762078]
[&(*it):0x00762088][it->a:1][&(*vec.rend()):0x00762078]
[&(*it):0x00762080][it->a:0][&(*vec.rend()):0x00762078]
4

3 に答える 3

5

push_back invalidates iterators when it causes size to exceed capacity:

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.

Basically, if you must push_back, make sure to reserve ahead of time so you don't invalidate your iterator.

于 2016-11-14T03:17:51.310 に答える
2

通常の (順方向で逆方向ではない) ベクトル反復子の場合、ベクトルに挿入すると、挿入点以降の任意の場所を指す反復子が無効になります。さらに、ベクトルのサイズを変更する必要がある場合は、すべての反復子が無効になります。

これだけでも問題を説明できます。ベクトルにスペースを予約していないため ( を呼び出すことによってvec.reserve(SIZE))、push_back呼び出しのいずれかがサイズ変更をトリガーし、イテレーターを無効にする可能性があり、後でそれらを使用しようとすると未定義の動作が発生する可能性があります。

ただし、逆イテレータはより複雑であり、同じ保証が逆イテレータには当てはまらず、挿入するとそれらが無効になる可能性があると思います。

内部的には、リバース イテレータは、それが指す要素の後の要素へのフォワード イテレータを保持します。逆参照されると、リバース イテレータはこのフォワード イテレータをデクリメントし、逆参照された値を返します。したがってrbegin()、内部には のコピーがありend()rend()のコピーがありbegin()ます。上記の順方向イテレーターの無効化のルールは、少なくとも、逆方向イテレーターの位置から 1 要素後までの任意の時点で挿入が発生した場合、逆方向イテレーターが無効になることを意味します。したがって、長さ 1 のベクトルでインデックス 0 を指すイテレータがある場合、push_backはインデックス 1 に挿入され、イテレータが無効になります。その後、その反復子を引き続き使用すると (後続のprintf呼び出しで逆参照する場合など)、未定義の動作が発生します。

未定義の動作は、何かが起こる可能性があることを意味し、非常に一般的に異なるシステムは異なる動作を生成します。このコードがシステムで初期ベクトル サイズが 5 の場合に期待どおりに実行されるからといって、他のシステムでも機能するとは思わないでください。未定義の動作を呼び出すコードは本質的に脆弱であり、避ける必要があります。

私 (Visual Studio 2015 を実行) ではprintf、ベクトルのサイズに関係なく、その行でクラッシュが発生します。サイズ変更の無効化の問題を解消するために呼び出すと、最初の長さが 1 のvec.reserve(10)場合にのみクラッシュします。vec

さらに、引数からアドレスを取得しようとしているだけであっても、引数で逆参照vec.rend()していますprintf。これは未定義の動作でもあります。(コードを実行するには、これをコメントアウトする必要がありました。そうしないと、呼び出しがなくても毎回クラッシュしpush_backます。)

于 2016-11-14T03:41:40.533 に答える
2

プログラムがクラッシュした可能性があります。コンテナーを反復しながらコンテナーを操作しています。

[&(*it):0x01ADC008][it->a:33][&(*vec.rend()):0x01ADC028]

ジャンク '33' が '13' のはずなのに見えます。

そして、なぜ終了イテレータを逆参照しようとしているのですか

&(*vec.rend())

これは基本的に、ベクターのサイズに関係なくジャンクになります。これは未定義の動作であり、アプリケーションをランダムにクラッシュさせます。

シャドウが指摘するように、反復する前にベクトルサイズを修正しますが、例にはセグフォールトを引き起こす他の問題があるため、コードを修正する方法はまだわかりません

于 2016-11-14T03:33:09.990 に答える