【问题标题】:Can I trust vector::size after an exception is thrown?抛出异常后我可以信任 vector::size 吗?
【发布时间】:2017-10-06 09:59:10
【问题描述】:

我试图了解异常如何影响std::vector。更准确地说,我想在抛出内存不足异常时检查向量的大小。

我的意思是这样的:

std::vector<int> v;
try {
    for(unsigned int i = 0; i < desiredSize; ++i)
        v.push_back(i);
}
catch (const std::bad_alloc&) {
    cerr << "Out of memory! v.size() = " << v.size() << endl;
    exit(EXIT_FAILURE);
}

这是一个好方法还是我应该使用我的自变量来跟踪向量的大小?

【问题讨论】:

  • v是什么类型?
  • 抱歉@jotik,已更新。这是一个std::vector。我想知道它的数据类型是否重要。
  • 请注意内存异常在 64 位机器上是罕见的。

标签: c++ function exception vector stl


【解决方案1】:

来自the documentation for std::vector::push_back

如果抛出异常(可能是由于Allocator::allocate() 或元素复制/移动构造函数/赋值),则此函数无效(强异常保证)。

所以在失败的情况下,导致异常的最后一个push_back 将被回滚,但其他一切都会好起来:你的向量将包含所有先前推送的元素,并且将处于一致状态。

【讨论】:

  • 啊哈,这样就行了!这意味着我不仅可以检查大小,还可以从异常中恢复并继续我的程序(如果大小对我来说仍然有意义的话)。谢谢问!
  • @gsamaras:异常安全是重用标准容器和类型的主要好处之一。
  • 是的,我同意@BoundaryImposition,但是当你内存不足时,你必须小心!
【解决方案2】:

根据[vector.modifiers]强调我的):

备注: 如果新容量大于旧容量,则会导致重新分配。 重新分配使引用序列中元素的所有引用、指针和迭代器无效。 如果没有发生重新分配,则插入点之前的所有迭代器和引用仍然有效。 如果除了T 的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符或任何InputIterator 操作引发异常,则没有任何影响。 如果在末尾插入单个元素时抛出异常并且TCopyInsertableis_­nothrow_­move_­constructible_­v&lt;T&gt; 为真,则没有效果。 否则,如果非CopyInsertableT的移动构造函数抛出异常,则效果未指定。

由于您的Tint(并且对整数的操作永远不会抛出),当它尝试为其内容分配新内存时,您只能从std::vector 获得内存不足错误,因此此函数具有抛出任何异常并在之后使用size() 时无效是一种完全有效的方法。

【讨论】:

    【解决方案3】:

    例外 如果抛出异常(可能是由于 Allocator::allocate() 或元素复制/移动构造函数/赋值),则此函数无效(强异常保证)。

    如果 T 的移动构造函数不是 noexcept 并且 T 不是 CopyInsertable 到 *this 中,vector 将使用抛出移动构造函数。如果它抛出,则放弃保证并且未指定效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      • 1970-01-01
      • 2015-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多