本文介绍了无需重新分配即可重用字符串流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图弄清楚如何重用 stringstream 对象,而无需每次在流中放入一些东西时重新分配底层字符串.我找到了这个答案,这促使我这样做:

I am trying to figure out how to reuse a stringstream object without the need to re-allocate the underlying string every time I put something in the stream. I have found this answer which led me to do this:

int main() {

        stringstream ss;
        int x;
        ss << "423";
        ss >> x; // x is now 423

        ss.clear();
        ss.seekg(0);
        ss.seekp(0);

        ss << "1";
        ss >> x; // x is now 123. Instead I want x to be 1.

        std::cout << x << std::endl;
}

不幸的是,这不起作用,因为第一遍的字符串内容仍然存在(第一遍后,字符串是 "423",第二遍后,它们是 123").但是,如果我在第二次放置后立即添加一个空格,事情似乎可以工作,如下所示:

Unfortunately, this doesn't work since the contents of the string from the first pass are still there (after the first pass the string is "423" and after the second pass they are "123"). However, if I add a space right after the second put, things seem to work, like this:

int main() {

        stringstream ss;
        int x;
        ss << "423";
        ss >> x; // x is now 423

        ss.clear();
        ss.seekg(0);
        ss.seekp(0);

        ss << "1";
        ss << " "; // add a space right after the desired value
        ss >> x; // x is now 1

        std::cout << x << std::endl;
}

在第二遍之后,字符串是"1 3".我对 I/O 库不是很熟悉,我想知道上述方法是否安全,或者它是否恰好适用于这个简单的例子,或者是否有更好的解决方案.实时代码此处.谢谢!

After the second pass the string is "1 3". I am not very familiar with the I/O library and I would like to know if the above approach is safe, or if it just happens to work in this trivial example, or if there are better solutions out there. Live code here. Thank you!

推荐答案

我使用 clang 进行了一些调查和实验,代码如下:

I did some investigations and experiments using clang with this code:

class LogHelper {
public:
    ~LogHelper() {
        std::cout << out.str() << '\n';
    }

    std::ostream &stream() {
        return out;
    }

private:
    std::ostringstream out;
};

#define LOG() LogHelper().stream() << __FUNCTION__ << '(' << __LINE__ << ")"
#define VAR(x) ", " #x "[" << x << ']'

class MyAllocator : public std::allocator<char> {
public:
    using base = allocator<value_type>;
    using base::allocator;

    value_type* allocate( std::size_t n, const void * hint) {
        LOG() << VAR(n);
        return base::allocate(n, hint);
    }

    value_type* allocate( std::size_t n ) {
        LOG() << VAR(n);
        return base::allocate(n);
    }

    void deallocate( value_type* p, std::size_t n ) {
        LOG() << VAR(n);
        base::deallocate(p, n);
    }
};

using MySStream = std::basic_stringstream<char, std::char_traits<char>, MyAllocator>;
using MyString = std::basic_string<char, std::char_traits<char>, MyAllocator>;

int main() {
    MySStream ss; // (MyString(255, '\0'));
    ss.clear();

    int x;
    ss << "423";
    ss << " 423";

    LOG();
    ss << " 423jlfskdfjl jfsd sdfdsfkdf dsfg dsfg dfg dfg dsfg df gdf gdfg dsfg dsfgdsfgds";
    LOG();
    ss >> x;

    ss.clear();
    ss.str({});

    ss.seekg(0);
    ss.seekp(0);

    ss << "1";
    ss >> x;

    std::cout << x << std::endl;
    LOG();

    return 0;
}

  • 你的渴望分配的例子 clang, visual studiogcc 7.3 忽略自定义分配器, gcc 8.x 不编译
  • main(55)
    allocate(34), n[48]
    allocate(34), n[96]
    deallocate(39), n[48]
    main(57)
    1
    main(70)
    deallocate(39), n[96]
    

    • 在流中预设长字符串 clang视觉工作室
    • allocate(34), n[256]
      allocate(34), n[256]
      deallocate(39), n[256]
      main(55)
      main(57)
      1
      main(70)
      deallocate(39), n[256]
      

      我有几个发现

      1. clang 和visual 的行为相同,gcc 对这段代码有一些棘手的问题.
      2. std::basic_stringstream 字符串缓冲区总是增长,从不收缩
      3. std::basic_stringstream 糟透了.您不能保留字符串大小或缓冲区大小,例如 std::string.自定义分配器只能按类型传递,不能按对象提供分配器.
      4. 为了减少分配,您必须在请求时设置大字符串,然后直到您成功为止,它的容量重新分配不会发生(第二个示例).
      5. 提供自定义分配器并没有多大帮助,它在获取结果字符串时添加了样板代码.在我的示例中,它主要用于记录分配和释放.
      6. ss.str({}); 不会引起分配.这里小字符串优化有帮助
      1. clang and visual behave in same meaner, gcc has some stang issues with this code.
      2. std::basic_stringstream string buffers always grows, never shrinks
      3. std::basic_stringstream sucks. You can't reserve string size or buffer size, like in case std::string. Custom allocator can be passed only by type, you can't provide allocator by object.
      4. To reduce allocations you have to set large string at the begging, then until you you will not succeed its capacity re-allocation will not happen (second example).
      5. providing a custom allocator doesn't help a lot and it adds boiler plate code when fetching result string. In my examples it is used mainly to log allocations and deallocations.
      6. ss.str({}); do not cause allocation. Here small string optimization helps

      结论:

      1. 您可以安全地执行 ss.str({}); 按照您的 SO 答案链接中的建议进行操作,并且不会导致分配.这里小字符串优化有帮助,事实是
      2. 自定义分配器不是很有帮助
      3. 在乞讨时设置大的虚拟字符串是非常有效的邪恶黑客
      4. 寻找替代方法应该是更好的方法(也许是提升 - 我没有测试过)
      5. Point 1 并且您的问题表明您没有进行任何测量,您的问题是基于个人假设.
      1. you can safely do ss.str({}); as recommended in linked by you SO answer and it will not cause allocation. Here small string optimization helps and the fact that
      2. custom allocator is not very helpful
      3. setting large dummy string at begging is quite effective evil hack
      4. finding alternative should be better approach (maybe boost - I didn't test it)
      5. Point 1 and your question shows that you didn't do any measurements and your question is based on personal assumptions.

      这篇关于无需重新分配即可重用字符串流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 12:51
查看更多