0
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,这显然不是最佳选择,但此时别无选择。

4

3 回答 3

2

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

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

简而言之,您发布的代码非常好。还有其他事情发生。

于 2011-03-26T08:02:04.193 回答
1

我认为你在那个错误之前做错了什么。一个std::vector::resize操作将要求内存,而堆很容易成为损坏的受害者。未定义行为的坏处在于,在错误发生一百万条执行指令后,症状就会变得可见(即“任何事情都可能发生”包括“什么都没有”)。

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

  1. 使用不明显的位模式初始化分配的内存(这是为了在有人使用未初始化的内存时发现问题,并且显然代码在找到零时有效)
  2. 在每个内存块之前和之后添加一些“安全区域”,并检查删除它是否未被覆盖(这是用于缓冲区溢出检测)
  3. 在释放时使用不同的特定模式填充内存(这是为了尝试捕获 read-after-delete 错误)
  4. 重用内存块并在重新分配或全局验证时检查已删除的内存模式是否仍然存在(这是为了捕获 write-after-delete 错误)
  5. 用信息标记每个块,__FILE__/__LINE__以检测谁在泄漏内存泄漏,并能够判断谁在使用删除后损坏的块。

我们还有一个内存检查例程,可以按需遍历所有内存块并检查一致性(通常我们只检查分配/解除分配)。对于绝望的情况,我们也可以只注销所有内存分配/释放的完整列表。

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

于 2011-03-26T08:30:34.840 回答
1

我是OP。

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

于 2011-03-26T10:43:22.323 回答