【问题标题】:std::string internal buffer corruption?std::string 内部缓冲区损坏?
【发布时间】:2013-06-16 05:58:30
【问题描述】:

我观察到 std::string 赋值运算符 (=) 导致写入 LHS 的访问冲突。在 MSVC++ 调试模式下,LHS 内部缓冲区指向无效地址。我不熟悉 MSVC++ std::string 的内部结构,但我之前假设内部缓冲区指针永远不应该是无效的。

使用 Visual Studio 调试器,我引用的内部缓冲区是 char[] 实例成员 std::string::_Bx::_Buf。这通常保存由std::string 对象表示的以空字符结尾的字符串的地址。看来std::string::_Bx._Ptr 也是指向此地址的char * 指针。

我在某些情况下经常遇到这种情况,但我无法确定此地址如何或何时变得无效。如果有东西破坏了这个值,调试器不会提醒我吗?有没有办法将 Visual Studio 调试器设置为在访问 std::string::_Bx::_Buf 进行写入时暂停?

在这种情况下,我无法提供SSCCE,因为我无法故意复制错误。调用错误的代码只是一个典型的实例变量中的字符串值赋值,比如:

class MyClass {
protected:
    std::string myValue;
public:
    void setValue(std::string value) {
        myValue = value; // ACCESS VIOLATION from std::string::operator=()
    }
};

class OtherClass {
    static myFunc() {
        std::string myString("some value");
        MyClass *myClass = new MyClass();
        myClass->setValue(myString); // ACCESS VIOLATION from setValue()
    }
};

是什么原因造成的?有没有人见过这个?有什么关于下一步看哪里的建议吗?

【问题讨论】:

  • 您发布的代码也有同样的问题吗?我们可以用它来检查吗
  • @QWR 不,该代码当然不应该有同样的问题。我只是快速打字,所以请原谅任何错别字等。这是一个玩具示例;见en.wikipedia.org/wiki/Mutator_method#C.2B.2B_example
  • 您是否在整个项目中使用 std::string 。或者您也将 char* 传递到某个地方。我怀疑这可能是原因。有如何在方法 stackoverflow.com/questions/175689/… 上实现显式关键字行为
  • 项目的其他部分使用char *,但没有任何代码使用char *。因为value 是按值传递的,所以我认为这不是罪魁祸首。这意味着MyClass::myValue 在某处被弄乱了,但它唯一被修改的地方是来自setValue()。我不确定explicit 或重载是否适用于此。

标签: visual-c++ access-violation assignment-operator stdstring


【解决方案1】:

s._Bx._Buf 不是指针,它是 std::string 用于保存小字符串的内部小缓冲区。这称为小缓冲区优化,或 SBO。 s._Bx 是缓冲区和_Ptr 的并集,它是指向堆缓冲区的指针,如果内部缓冲区太小则分配该指针。所以对于小字符串,s._Bx._Ptr应该是无效的;毕竟,它的存储是用于小字符串的。

无论如何...如果您遇到访问冲突,一切都不好。在这种情况下,最可能的原因是您不小心弄乱了 std::string 的内存,很可能是由于某些缓冲区溢出或某处释放后使用。有趣的不是任务,而是它之前发生的事情。

【讨论】:

  • 感谢您提供有关内部缓冲区的信息。在这种情况下如何/在哪里定义“小”? (你的意思是“所以对于小字符串,s._Bx._Buf 应该是无效的?编辑:我现在明白了)如果我不小心弄乱了std::string,有没有办法让调试器提醒我的记忆?
  • 1) “小”是由 MS 工程师为找到最佳尺寸所做的实验定义的。代码中可能有一些常数。 2) 不,我不是那个意思。 _Ptr 应该是无效的,因为 _Buf 包含字符串数据并且它位于同一个内存中。 3)stackoverflow.com/questions/621535/what-are-data-breakpoints
  • 详述3),在你最初创建字符串后设置一个普通断点,用调试器找出它的地址,并在那里设置一个数据断点。
  • 好的,谢谢...在任何给定时刻,_Buf_Ptr 中的至少一个应该无效吗?
  • 你是对的。在错误发生之前我错过了这一点,在某个点可以删除 MyClass 的实例(以我在 OP 中的示例),在这种情况下就是这种情况。该实例是通过与myFunc() 中的指针不同的指针删除的。我很惊讶之后我仍然能够调用myClass->setValue(),尽管事实上myClass 引用了一个刚刚被删除的地址,并且直到尝试访问实例成员的内部缓冲区才出现访问冲突发出。感谢string 上的信息!
猜你喜欢
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
相关资源
最近更新 更多