Soul-crushing C ++ std :: vector :: resize()访问冲突错误

时间:2011-03-26 05:17:12

标签: c++ resize access-violation stdvector

class SimpleVariant
{
public:
    SimpleVariant()  { /*...*/ };
    // ...
};


struct VariantBlock
{
    int nRows, nCols;
    vector<SimpleVariant> theData;
};



void dumbFunction( VariantBlock& theBlock, int nRows, int nCols )
{
    // ...
    cout << "theBlock.nRows= " << theBlock.nRows 
         << ", theBlock.nCols= " << theBlock.nCols
         << ", theBlock.theData.size() " << theBlock.theData.size();

    theBlock.theData.resize( nRows * nCols );   
       // throws Access Violation Exception

    // ...
} 

输出返回nRows = 61,nCols = 5,size()= 0,这正是在抛出访问冲突异常之前的那一点。

我正在使用MSVC6,这显然不是最佳选择,但此时别无选择。

3 个答案:

答案 0 :(得分:2)

我最近不得不升级一些最初为Visual C ++ 6编写的代码。该代码有问题,因为VC ++ 6没有处理可以正确绑定到引用的内容。这是在黑暗中拍摄的东西,但是你是否正在const VariantBlock传递给dumbFunction?在C ++规则下,这是非法的,但我强烈怀疑VC ++ 6会出错。

另一种可能性是某种运行时不匹配。如果(1)VariantBlock分配在一个模块中,(2)dumbFunction来自不同的模块,(3)它们是使用不同的设置编译的,可能是不同的编译器的版本,然后您将看到这种行为(resize()分配新内存,将所有内容复制到它,然后去释放旧内存,除了旧内存分配在不同的运行时,所以程序barfs)。

简而言之,您发布的代码完全没问题。还有其他事情要发生。

答案 1 :(得分:1)

我认为你在错误之前做错了什么。 std::vector::resize操作将要求内存,堆很容易成为腐败的受害者。关于未定义行为的坏处是,在错误发生后,症状可以看到一百万个执行指令(即“任何事情都可能发生”包括“无”)。

我们有一个“调试内存管理器”,它重新定义了全局分配器,并且可以对腐败进行大量检查:

  1. 使用非显而易见的位模式初始化已分配的内存(这是为了发现当有人使用未初始化的内存时出现问题,显然代码在找到零时工作)
  2. 在每个内存块之前和之后添加一些“安全区域”并检查删除它是否已被覆盖(这是用于缓冲区溢出检测)
  3. 在解除分配时使用不同的特定模式填充内存(这是为了尝试捕获读后删除错误)
  4. 重用内存块和重新分配或全局验证检查已删除的内存模式仍然存在(这是为了捕获写后删除错误)
  5. 使用__FILE__/__LINE__信息标记每个块,以检测是谁泄漏了内存泄漏,并能够告诉谁正在使用删除后损坏的块。
  6. 我们还有一个内存检查例程,按需可以遍历所有内存块并检查一致性(通常我们只检查分配/解除分配)。我们还可以为绝望案例注销所有内存分配/解除分配的完整列表。

    不幸的是,对于第(5)点,C ++语法难以检测,因此我们实际上不使用new而是使用最终扩展为放置分配的xnew宏;这也意味着我们无法检测标准库中分配的内存块(我们存储了在库中分配之前在程序中进行分配的最后一行源代码)。

答案 2 :(得分:1)

我是OP。

问题是来自调用函数的内存损坏。