如何将vector <t> :: reverse_iterator与一个元素一起使用

时间:2016-11-14 02:52:59

标签: c++ vector reverse-iterator

我使用了poll()和std :: vector。 注册听socket。

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]

如果vector有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]

3 个答案:

答案 0 :(得分:5)

push_back invalidates iterators导致size超出容量时

  

如果new size()大于capacity(),则所有迭代器和引用(包括last-the-end迭代器)都将失效。否则只有过去的迭代器无效。

基本上,如果您必须push_back,请务必提前reserve,这样您就不会使迭代器失效。

答案 1 :(得分:2)

你的程序很可能已经崩溃了。您正在迭代它时操纵容器。

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

你可以看到垃圾&#39; 33&#39;虽然它应该是&#39; 13&#39;

为什么你甚至试图取消引用最终迭代器

&(*vec.rend())

无论矢量大小如何,这基本上都是垃圾。它是一个未定义的行为,会随机崩溃您的应用程序。

由于影子指出在迭代之前修复了矢量大小,但我仍然不确定如何修复代码,因为您的示例有其他问题会导致seg错误

答案 2 :(得分:2)

对于正常(向前,而不是反向)向量迭代器,插入向量会使指向插入点或其后任何位置的任何迭代器无效。此外,如果必须调整向量的大小,则所有迭代器都将失效。

这可以解释你的问题,因为你没有在你的向量中保留空间(通过调用vec.reserve(SIZE)),你的任何push_back调用都可能触发调整大小并使你的迭代器无效,这将是当您尝试之后使用它们时会导致未定义的行为。

但是,反向迭代器更复杂,并且相反的迭代器也没有相同的保证,我相信任何插入都可能使它们失效。

在内部,反向迭代器在它指向的元素之后保存向前迭代器。取消引用时,反向迭代器递减此转发迭代器并返回其解除引用的值。因此rbegin()内部有end()的副本,rend()begin()的副本。前向迭代器失效的上述规则然后暗示,如果插入发生在反向迭代器的位置之后的一个元素之前的任何点处,则反向迭代器至少将失效。因此,如果在长度为1的向量中有一个指向索引0的迭代器,push_back将插入索引1,这将使迭代器无效。如果然后继续使用该迭代器(例如在随后的printf调用中取消引用它),那么您将有未定义的行为。

未定义的行为意味着任何事情都可能发生,而且通常不同的系统会产生不同的行为。 不要认为只是因为此代码在系统上按预期运行,初始向量大小为5,它将在其他系统上运行。任何调用未定义行为的代码本质上都是脆弱的,应该避免。

对我来说(运行Visual Studio 2015),无论向量的大小如何,我都会在printf行遇到崩溃。如果我致电vec.reserve(10)以消除调整大小失效问题,那么只有当vec最初为长度为1时,它才会崩溃。

此外,您在vec.rend()参数中取消引用printf,这也是未定义的行为,即使您只是想从中获取地址。 (我不得不对此进行注释以使代码运行,否则即使没有push_back调用它也会崩溃。)