2016-11-14 80 views
0

我用poll()与std :: vector。 注册收听套接字。如何使用向量<T> :: reverse_iterator与一个元素

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] 
+0

Btw回答为什么这适用于1,2,4矢量大小的原因是由于矢量如何重新分配自己。我假设你的1,2,4矢量大小是你准备矢量的第一个循环。 矢量随着size_needed + size_needed/2增长为1,2,4,它需要通过使先前的分配无效并且您的矢量变为无效来重新分配。 对于5的矢量容量应该是6(4 + 4/2)在那个时候有足够的空间没有移动分配的项目,所以它会工作。 – user3279954

回答

5

push_back invalidates iterators时,它会导致size超过容量:

如果新的大小()比容量大(),那么所有的迭代器和引用(包括过去的最末端迭代器)是无效。否则只有最后一个迭代器失效。

基本上,如果您必须提前push_back,请确保提前reserve,以免您的迭代器失效。

+0

还有更多。反向迭代器比正向迭代器更容易失效,即使在获得反向迭代器之前调用了vector :: reserve,上面的代码仍会使迭代器无效。 –

+0

谢谢,ShadowRanger。我修复了我的代码。在做push_back之后,我重新分配了迭代器值。 'vec.push_back(t); it = vec.rbegin()+ index + i; ' –

2

您的程序很有可能已经崩溃。您仍在迭代容器时操纵容器。

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

你可以看到垃圾'33',而它应该是'13'。

为什么你甚至试图取消引用结束迭代

&(*vec.rend()) 

这基本上将是一个垃圾不论矢量大小的。它是一个未定义的行为,会随机地使应用程序崩溃。

由于阴影点出固定矢量大小迭代之前,但我仍然不知道如何将解决您的代码作为你的例子有,这将导致赛格故障

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时崩溃。

此外,你在你的printf参数,这也是不确定的行为提领vec.rend(),即使你只是想获得一个地址出来。 (我不得不评论这个让你的代码运行,否则它会崩溃每次,即使没有push_back电话。)

+0

在我的系统上(使用Visual Studio 2015,调试版本),我得到一个调试断言失败,给出错误“表达式:向量迭代器不可递减”。我怀疑'&(* vec.rend())'相当于'&(*(vec.begin() - 1))',而vec.begin() - 1是非法的。 –

+0

不,“vec.begin() - 1”只有在您取消引用vec.rend()'时才会发生。而'it!= vec.rend()'只会比较'it'的内部前向迭代器和'vec.rend()'的内部前向迭代器,而不需要减少内部前向迭代器。 –

+0

无论如何,这并不重要,因为它是未定义的行为,因为不符合迭代器'operator *'的前提条件。与取消引用不存在的对象无关。我猜你使用了“解除引用”来表示“应用'*'运算符”,但'*'运算符首先是一个函数调用,并且只有满足前提条件,我们才能讨论函数的副作用,例如实际执行解引用。 –

相关问题