【问题标题】:destruction of std::stringbuf causing access violation破坏 std::stringbuf 导致访问冲突
【发布时间】:2023-03-15 09:41:01
【问题描述】:

我有一个大致如下所示的 c++ 类(参见下面的代码)。它有一个输入缓冲区和一个使用 std::stringbuf 的输出缓冲区。因为我还想访问原始缓冲区,所以我使用 std::stringbuf.pubsetbuf() 将底层缓冲区设置为我自己的用户定义字节数组。

一切似乎都运行良好,直到我不再需要该对象,但当该对象被破坏时,它会导致我的程序因访问冲突而崩溃。

我将其追溯到如下所示的一段代码。在我看来,stringbuf 正在以某种方式清理我的用户定义的字节数组本身?当我删除类的 destrcutor 中的代码以释放我之前在构造函数中分配的字节数组时,我的程序不会崩溃。

请问有什么建议吗?我错误地使用了 std::stringbuf 吗?我正在使用 Borland 5.0 编译器(我知道它是一个非常古老且过时的编译器,但我必须坚持使用这个编译器一段时间)。

class SomeClass {

private:

    char *mIBuf;
    char *mOBuf;

    std::stringbuf mIBufStream;
    std::stringbuf mOBufStream;

public:

    SomeClass(int iBufSize, int oBufSize) :
      mIBuf(), mOBuf(),
      mIBufStream(), mOBufStream()
    {
        mIBuf = (char*)malloc(iBufSize);
        mOBuf = (char*)malloc(oBufSize);

        mIBufStream.pubsetbuf(mIBuf, iBufSize);
        mIBufStream.pubseekpos(0);

        mOBufStream.pubsetbuf(mOBuf, oBufSize);
        mOBufStream.pubseekpos(0);
    }

    virtual ~SomeClass()
    {
        free(mIBuf);
        free(mOBuf)
    }

};

【问题讨论】:

  • 标准规定stringbuf::setbuf(这是pubsetbuf 所调用的)具有实现定义的行为。您是否有针对您的具体实施的文档?
  • 另外,您似乎没有粘贴实际代码而是重新输入了它?并且在这个过程中对标点符号不是很小心。
  • @BenVoigt,是的,代码标签错位把我扔了:) ...编辑评论
  • @BenVoight:是的,确实,我重新输入了我的代码,因为我想让示例代码看起来尽可能干净,以便在此处阅读。没有太注意标点符号。对此感到抱歉。我已经更正了标点符号。我没有关于我的具体实现的文档。也许我可以在某个地方找到它,但现在我不知道在哪里可以找到它。
  • 基类std::streambuf的析构函数负责删除指针。

标签: c++ arrays stl buffer access-violation


【解决方案1】:

根据标准,stringbuf 没有自己的析构函数,streambuf 的析构函数什么也不做。您的旧编译器和库可能会也可能不会遵循它;有证据表明它不是。

嗯,原则上你做错了什么。当您调用 pubsetbuf 时,您将授予该对象使用该缓冲区的权限,只要该对象存在,或者直到您再次更改其缓冲区。

看看你的析构函数,你并没有遵守协议。

virtual ~SomeClass()
{
    free(mIBuf);
    free(mOBuf); // <- missing semicolon in your code

    // the stringbuf objects are still alive here
}   // they get automatically destroyed here

一种选择是在释放缓冲区之前安排 stringbuf 对象被销毁(char* 缓冲区释放将需要由辅助类完成,该类是基类或在 @987654327 之前声明的成员@ -- std::vector&lt;char&gt; 会是一个不错的选择)。

或者,您可以让stringbuf 知道您正在撤销其使用您的内存的权限:

virtual ~SomeClass()
{
    mIBufStream.pubsetbuf(0, 0);
    mOBufStream.pubsetbuf(0, 0);

    // the stringbufs cannot use your memory any longer

    free(mIBuf);
    free(mOBuf);
}

【讨论】:

  • 感谢您的回答。实际上,我已经尝试了您的建议。我之前使用的是 std::vector 而不是 char* 缓冲区(但为了隔离我的问题的原因,我替换了那段代码)。使用 pubsetbuf(0, 0) 撤销对 std::stringbuf 的权限似乎不能解决我的问题(至少不能解决我正在使用的编译器和库)。所以,我怀疑我的 Borland stl 库可能没有遵循标准。
  • @cpirate:如果您在再次更改缓冲区后仍看到崩溃,我怀疑存在一些内存损坏导致您对 free 的调用失败,实际上不是 @ 的任何尝试987654332@ 在销毁期间使用或释放​​缓冲区。
  • @BenVoight:嗨,我已经进一步测试了这个示例代码。我把这个类提取出来,放到一个小的测试程序中。没有其他可能破坏程序的代码。一个版本使用 Visual Studio 2013 编译,另一个使用 Borland 5.0 编译。 Visual Studio 似乎在没有崩溃的情况下执行该程序,Borland 在那里崩溃了它。所以,我现在很确定是 Borland stl 库实现不符合标准实现。我怀疑当我将 0 作为参数传递时,Borland 版本中的 std::stringbuf.pubsetbuf() 什么都不做。
【解决方案2】:

好吧,回答我自己的问题...(感谢 Ben Voight 的有用建议)。在其他人证明我错之前,我得出的结论是我的问题是特定于实现的,并且 Borland 5.0 STL 库可能不符合标准。

我测试了我的示例类。我将其提取并放入一个小测试程序中,如下所示(没有其他可能破坏内存的代码)。我用 Visual Studio 2013 编译了 1 个版本,用 Borland 5.0 编译了另一个版本。用 Visual Studio 编译的那个运行得很好。用 Borland 编译的版本在第 1 次迭代后崩溃。

#include <iostream>

包括

类 SomeClass {

char *mIBuf;
char *mOBuf;

std::stringbuf mIBufStream;
std::stringbuf mOBufStream;

公开:

SomeClass(int iBufSize, int oBufSize) : mIBuf(NULL), mOBuf(NULL), mIBufStream(), mOBufStream() {
    mIBuf = (char*)malloc(iBufSize);
    mOBuf = (char*)malloc(oBufSize);

    mIBufStream.pubsetbuf(mIBuf, iBufSize);
    mIBufStream.pubseekpos(0);

    mOBufStream.pubsetbuf(mOBuf, oBufSize);
    mOBufStream.pubseekpos(0);
}

virtual ~SomeClass() {
    mIBufStream.pubsetbuf(0, 0);
    mOBufStream.pubsetbuf(0, 0);

    free(mIBuf);
    free(mOBuf);
}

};

int main(int argc, char* argv[])
{
    for (int x = 0; x < 1000; x++) {
        SomeClass SomeClass(128 * 1024, 128 * 1024);
        std::cout << "Pass " << x + 1 << std::endl;
    }

    return 0;
}

【讨论】:

    猜你喜欢
    • 2012-05-22
    • 2016-06-15
    • 2023-03-08
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    相关资源
    最近更新 更多