重复使用字符串流而无需重新分配

时间:2018-08-24 15:42:16

标签: c++ stringstream

我试图弄清楚如何重用stringstream对象,而无需每次我在流中添加内容时都重新分配基础字符串。我发现this answer促使我这样做:

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")。但是,如果我在第二个位置之后添加一个空格,则似乎可以正常工作,如下所示:

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库不是很熟悉,我想知道上述方法是否安全,或者在这个琐碎的示例中它是否恰好可行,或者是否有更好的解决方案。实时代码here。谢谢!

1 个答案:

答案 0 :(得分:0)

我使用带有以下代码的clang进行了一些调查和实验:

测试代码

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;
}
main(55)
allocate(34), n[48]
allocate(34), n[96]
deallocate(39), n[48]
main(57)
1
main(70)
deallocate(39), n[96]
allocate(34), n[256]
allocate(34), n[256]
deallocate(39), n[256]
main(55)
main(57)
1
main(70)
deallocate(39), n[256]

我有几个发现

  1. c和视觉行为相同,gcc在此代码中存在一些纠结问题。
  2. std::basic_stringstream字符串缓冲区始终增长,从未缩小
  3. std::basic_stringstream很烂。您不能保留字符串大小或缓冲区大小,例如,std::string。自定义分配器只能按类型传递,不能按对象提供分配器。
  4. 要减少分配,您必须在乞讨时设置大字符串,然后直到您不成功时,才不会重新分配其容量(第二个示例)。
  5. 提供自定义分配器并没有太大帮助,并且在获取结果字符串时会添加样板代码。在我的示例中,它主要用于记录分配和释放。
  6. ss.str({});不引起分配。小字符串优化在这里有帮助

结论:

  1. 您可以按照您的答案链接中的建议安全地进行ss.str({});的操作,这不会导致分配。在这里,小的字符串优化会有所帮助,并且
  2. 自定义分配器不是很有帮助
  3. 在乞讨时设置大型虚拟字符串是非常有效的邪恶手段
  4. 寻找替代方法应该是更好的方法(也许可以提高-我没有测试过)
  5. 指向1,您的问题表明您没有进行任何度量,并且您的问题基于个人假设。