reusing a stringstream without re-allocation

浪尽此生 提交于 2021-02-10 07:49:28

问题


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

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

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!


回答1:


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

Test 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;
}
  • your example with longing allocations clang, visual studio, gcc 7.3 ignores custom allocator, gcc 8.x do not compile
main(55)
allocate(34), n[48]
allocate(34), n[96]
deallocate(39), n[48]
main(57)
1
main(70)
deallocate(39), n[96]
  • preset long string on stream clang, visual studio
allocate(34), n[256]
allocate(34), n[256]
deallocate(39), n[256]
main(55)
main(57)
1
main(70)
deallocate(39), n[256]

And I have couple findings

  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

Conclusions:

  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.


来源:https://stackoverflow.com/questions/52007781/reusing-a-stringstream-without-re-allocation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!