【问题标题】:crash when using stl vector at instead of operator[]使用 stl 向量 at 而不是 operator[] 时崩溃
【发布时间】:2010-05-26 09:36:57
【问题描述】:

我有一个方法如下(来自一个实现 TBB 任务接口的类 - 虽然目前不是多线程) 我的问题是访问向量的两种方式导致了完全不同的行为——一种有效,另一种导致整个程序非常壮观地爆炸(这是一个插件,通常主机会捕获崩溃——但这种需要主持人节目也出来了!正如我所说的非常壮观)

void PtBranchAndBoundIterationOriginRunner::runOrigin(int origin, int time) const // NOTE: const method
{
    BOOST_FOREACH(int accessMode, m_props->GetAccessModes())
    {
        // get a const reference to appropriate vector from member variable
        // map<int, vector<double>> m_rowTotalsByAccessMode;
        const vector<double>& rowTotalsForAccessMode = m_rowTotalsByAccessMode.find(accessMode)->second;

        if (origin != 129) continue; // Additional debug constrain: I know that the vector only has one non-zero element at index 129

        m_job->Write("size: " + ToString(rowTotalsForAccessMode.size()));
        try {
            // check for early return... i.e. nothing to do for this origin 
            if (!rowTotalsForAccessMode[origin])    continue; // <- this works
            if (!rowTotalsForAccessMode.at(origin)) continue; // <- this crashes
        } catch (...) {
            m_job->Write("Caught an exception"); // but its not an exception
        }

        // do some other stuff
    }
}

我讨厌不提出明确定义的问题,但目前我最好的措辞是:“WTF?”

我正在使用 Microsoft (R) Visual Studio 版本 9.0.21022.8 使用 Intel C++ 11.0.074 [IA-32] 进行编译,并且我的向量实现具有

const_reference operator[](size_type _Pos) const
{   // subscript nonmutable sequence

#if _HAS_ITERATOR_DEBUGGING
    if (size() <= _Pos)
    {
        _DEBUG_ERROR("vector subscript out of range");
        _SCL_SECURE_OUT_OF_RANGE;
    }
#endif /* _HAS_ITERATOR_DEBUGGING */
    _SCL_SECURE_VALIDATE_RANGE(_Pos < size());

    return (*(_Myfirst + _Pos));
}

(迭代器调试已关闭 - 我很确定)和

const_reference at(size_type _Pos) const
{   // subscript nonmutable sequence with checking
    if (size() <= _Pos)
        _Xran();
    return (*(begin() + _Pos));
}

所以我能看到的唯一区别是 at 调用开始而不是简单地使用 _Myfirst - 但这怎么可能导致行为如此巨大的差异?

更新

索引在范围内 - 大小打印为 377,索引限制为 129。

成员变量有对应accessMode的入口

为了澄清@nikko 的建议,整件事都包含在以下内容中:

map<int, vector<double>>::const_iterator it = m_rowTotalsByAccessMode.find(accessMode);
if (it != m_rowTotalsByAccessMode.end())
{
    ...

更新 我已将我的编译器升级到最新版本 11.1.065,并且不再发生这种情况。好像哪里有点奇怪。

【问题讨论】:

  • 对于更新: "index is constrained to 129" ,你不是在检查 &gt;= 而是在做 != 。这是故意的吗?
  • 如果你看一下代码中的注释,它看起来就像是故意的。
  • 我看到了评论,但更新中的声明让我有点困惑。
  • 如果你在一个简单的测试程序中这样做会发生什么?也许你有一些内存损坏,或者插件编译有问题。您是否处理插件和主程序之间共享的对象?
  • @nikko,我还没有尝试在测试程序中隔离它。我认为内存损坏是最可能的答案,但我不知道从哪里开始 - 通常如果是内存,你可以修复症状(在与 [] 时),然后问题会在其他地方弹出 - 但在这种情况下我不能让它崩溃,除了这条线 - 我什至打开了多线程并用 8 个线程运行 - 坚如磐石:(

标签: c++ stl vector crash


【解决方案1】:

我没有看到您在哪里检查 rowTotalsForAccessMode 是否有效。也许您的“m_rowTotalsByAccessMode.find(accessMode)”不起作用。

您应该对照迭代器 end() 检查 .find() 的结果,看看它是否有效

【讨论】:

  • +1 我认为 OP 最终会发现 []-version 没有崩溃是侥幸。
  • 好点 nikko,但出于问题的目的,它已被发现...我明确填充它
  • +1 给 Nikko,这两个也吸引了我的眼球。所以实际上这两种情况都存在问题,只是带有'[]'的那个会默默地执行ABW,而带有'at()'的那个会抛出。 uncaugt 异常导致程序在 *nix 上“中止”,但不确定它如何映射到 MS。
  • @bobah:但是有 catch(...) 应该捕获异常,除非此代码在堆栈展开过程中执行。
  • @bobah:除了在调用点不是例外......这是一个可怕的核心转储......但你是对的 - 如果 .find() 返回 end() 那么我试图尊重结束指针,这会使事情进入非常糟糕的状态。
【解决方案2】:

您不能在调试器中单步执行程序(进入at)并查看导致崩溃的原因吗?有两种选择:

  1. rowTotalsForAccessMode 无效
  2. origin 超出范围

【讨论】:

  • 对不起...仅在发布模式下出现。
  • 你应该也可以单步发布,不是吗?
  • Visual Studio 在发布模式下做了一些奇怪的跳跃。我没有例子,但如果内存对我有用(呵呵),我通常会在内存损坏时看到它(我猜是调试模式补偿?)
  • 不,不是这样。调试器在发布模式下确实会跳动一点,但这是因为优化可能已经移动/删除/内联/展开代码等。但这并不能阻止您单步执行函数并找到崩溃点。
  • 很可能所有的标准库代码都是内联的。我不确定调试器会如何处理这个问题
【解决方案3】:

我讨厌回答自己的问题,但这似乎是需要的情况。正如更新中所说,我下载并安装了最新的 intel c++ 编译器并从头开始重新编译,这似乎已经解决了问题。我还使用 11.0.074 编译器从头开始重建了整个项目,以排除其中一个二进制文件的损坏;即使是干净的构建也会导致崩溃!

我将在英特尔论坛上跟进此问题,感谢所有为此问题付出时间和精力的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多