【问题标题】:Strange access violation at vector indexer矢量索引器出现奇怪的访问冲突
【发布时间】:2011-07-05 09:25:09
【问题描述】:

首先介绍一下:我目前正在研究 C++ 兼容性,这意味着能够运行具有不同编译器选项的项目。因此,我使用一个发布 DLL 和一个链接到该其他项目的调试应用程序进行测试。 大多数问题都是在使用 STL 时出现的,所以我必须确保两个项目都只使用它们自己的 STL 版本。 这就是为什么我有一个包装类,它可以由 std::vectors、std::lists 等构建,但只包含一个完全兼容的数组。现在我可以将值包装在一个数组中,然后在另一端将它们解包到一个有效的 STL 对象中。

现在让问题更接近一点:有些类包含 STL,但也需要包装到数组中。所以我也必须包装内部 STL 对象,这意味着添加一个 tag 并将其保存在关联的数组元素旁边。

建立这个包装类完全没有问题,但是解压它会在向量类中发生访问冲突而崩溃:

   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));  <---- HERE
        }

此时的执行代码是这样的:

template<class T>
struct mwContainerItem
{
    T m_element;
    void * m_tag;
};

template<class T>
class mwContainer
{
    STLList ToList()
    {
        STLList l;
        for(size_t i=0; i<m_size; ++i) <---- It crashes when accessing m_size
        {
            l.push_back(m_elements[i].m_element); <---- It also crashes when accessing m_elements
        }
        return l;
    }

    mwContainerItem<T>* m_elements;
    size_t m_size;
};

关于它的奇怪之处在于我正在解压缩一个 std::list,但它在 std::vector 中崩溃了。查看我有一个由 std::vector 包含的类,而这个类包含一些没有 STL 的基本类的 std::list。所以解包意味着将外部数组复制到 std::vector 中,将每个内部数组复制到 std::list 中。

此错误仅在我使用不同的编译器选项时发生,在同一个项目中打包和解包工作正常。

我真的希望任何人都可以帮助我,因为我不知道。

问候

【问题讨论】:

  • 不幸的是,我相信如果不使用相同的选项进行编译,就无法解决这个问题。见:stackoverflow.com/questions/4446620/…
  • 有些事情你必须知道,但是在对我的代码做了一些更改之后,我能够用这种方法编译它。但它只是开始在一个简单的“递归包装”上崩溃,如果这个概念适用于没有内部 STL 对象的示例,我根本看不到问题。
  • @Marcel 为什么您认为数组与不同的打包选项兼容?通常他们不会
  • @user396672 不是吗?在我的信念中,数组保存在指针的位置 + i * 对象的大小。我不知道为什么无论您使用 Release 还是 Debug,这都会有所不同。不过我会马上检查的。
  • @Marcel 因为对象的大小可能不同。编译器根据结构包装添加一些填充

标签: c++ stl vector access-violation binary-compatibility


【解决方案1】:

您真的需要两个版本的 STL 吗?我的意思是,您是否使用两个不同的编译器和两个不同的 STL 实现来构建这两个项目?混合调试版本和发布版本时,问题通常来自两个不同的堆。然后,试图释放在另一个模块中分配的内存,将导致错误。如果您遇到这种情况,您可以尝试另一种方法 - 两者都使用相同的堆。

如果您可以控制这两个项目,您可以从 DLL 中导出一个分配器(和匹配的释放器),并在 EXE 中使用它。这样,内存管理将在单个堆上完成,构建类型无关紧要。您可以在operator new、向量/列表分配器等中使用它。

这可能无法解决打包问题(谁会更改打包设置?...),但在使用多个堆时这是您想要的。

【讨论】:

  • 是的,我真的需要两个版本的 STL。不用担心我使用了两个堆,因为我找到了一种处理内存分配的方法。打包设置到底是什么意思?我谈到了编译器设置的差异,例如 Debug 和 Release,这使得它们很难一起编译。
  • @Marcel Bonzelet 我指的是数据对齐,使用pragma pack 或/Zp 开关。确保它们是相同的——如果你不知道它们是做什么的,那么它们真的没有理由不具有(相同的)默认值。
  • 我在两个项目中都使用默认值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-23
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 2017-03-27
相关资源
最近更新 更多