【问题标题】:EXC_BAD_ACCESS using << on stringstream objectEXC_BAD_ACCESS 在字符串流对象上使用 <<
【发布时间】:2017-05-18 13:13:08
【问题描述】:

我正在编写一个代码,我需要将一个大字符串写入内存。 我使用了一个 stringstream 对象来执行此操作,但发生了一些奇怪的事情:即使底层字符串缓冲区的大小没有超过字符串对象的最大大小,我的程序也会因 BAD_ACCESS 错误而崩溃。

我已经创建了一个这样的测试程序:

#include <sstream> // std::stringstream
#include <iostream> // std::cout

int main(int argc, const char * argv[]) {

    std::stringstream stream;
    std::string string;
    std::cout << "Max string size: " << string.max_size() << "\n";

    for (int i = 0; true; i++) {
        if (i >= 644245094) {
            stream.seekg(0, std::ios::end);
            std::stringstream::pos_type size = stream.tellg();
            stream.seekg(0, std::ios::beg);
            std::cout << "Size of stringstream: " << size << "\n";
        }
        stream << "hello";
    }

    return 0;
}

循环中的if (i &gt;= 644245094) 仅用于在程序崩溃之前打印字符串流缓冲区的大小。我已经使用我的调试器查看了上次迭代的次数,并在崩溃发生之前用它来打印缓冲区的大小。

这是我得到的输出:

Max string size: 18446744073709551599
Size of stringstream: 3221225470

此后程序崩溃。

我认为原因可能是因为该程序填满了我计算机的 RAM,但该程序使用的内存约为 6.01GB,因此不足以填满我的 RAM。作为记录,我有一台 16GB 内存的 Macbook Pro。

可能是什么问题?我是否错过了 &lt;&lt; 运算符的工作原理?

提前谢谢你!

【问题讨论】:

    标签: c++ string stringstream


    【解决方案1】:

    当 std::stringstream 变满和失败时的行为可能在所有平台上都不一致。

    我修改了您的代码并在 Yocto 3.19.0-32 64 位和 gcc 5.4.1 上运行。我没有抛出异常,而是流设置了它的故障模式位之一。

    我运行的代码是:

    #include <sstream>    // std::stringstream
    #include <iostream>   // std::cout
    
    std::stringstream::pos_type get_size(std::stringstream& stream)
    {
        stream.seekg(0, std::ios::end);
        std::stringstream::pos_type size = stream.tellg();
        stream.seekg(0, std::ios::beg);
        return size;
    }
    
    int main(int argc, const char * argv[])
    {
        std::stringstream stream;
        std::string string;
        std::cout << "Max string size: " << string.max_size() << std::endl;
        std::stringstream::pos_type size;
    
        for (unsigned long i = 0; true; ++i)
        {
            size = get_size(stream);
            stream.write("x", 1);
            if (stream.fail())
            {
                std::cout << "Fail after " << i + 1 << " insertions" << std::endl;
                std::cout << "Size of stringstream just before fail: " << size << std::endl;
                break;
            }
        }
    
        size = get_size(stream);
        std::cout << "Size of stringstream just after fail: " << size << std::endl;
    
        return 0;
    }
    

    我得到以下输出,这表明我的字符串流已填充并失败了 56 个字节,不足 8GB:

    Max string size: 4611686018427387897
    Fail after 8589934536 insertions
    Size of stringstream just before fail: 8589934535
    Size of stringstream just after fail: -1
    

    你能不使用不同的容器并预先分配内存,而不是使用这么大的字符串流吗?

    【讨论】:

    • 好吧,现在我的解决方法是在我的实例太大时直接将字符串打印到输出文件中,而不使用字符串流。我应该使用哪种容器而不是 stringstream?
    • @jackscorrow 如果直接写入文件对您有用,那么也许就这样吧。或者,如果您提前知道最终大小,您可以从一个空的 std::string 开始并调用它的 reserve() 成员函数来预分配内存,然后将您的数据附加到它。这样,如果没有足够的内存,您会提前抛出 bad_alloc。如果你只需要一个缓冲区并且不需要 std::string 提供的增值字符串处理函数,你可以对 std::vector 做同样的事情。
    • 不幸的是我不能使用字符串。我将不得不更改很多代码行,而我没有时间。关于我的问题,我发现并不是我在代码中犯了错误,而是我猜stringstream 的工作方式。我会看看将来是否可以按照您的建议更改代码。我正在考虑回答的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 2015-10-08
    • 2012-03-25
    • 1970-01-01
    • 2011-10-12
    • 2020-04-22
    • 1970-01-01
    相关资源
    最近更新 更多