我使用 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;
}
- 你的渴望分配的例子clang https://wandbox.org/permlink/dIz5RLGNzq2BosLz, 视觉工作室 http://rextester.com/HXCJ27140, gcc 7.3 忽略自定义分配器 https://wandbox.org/permlink/HscWOqsur0HtCHdC, gcc 8.x 无法编译 https://wandbox.org/permlink/u2ygBmSJ96RNcUBg
main(55)
allocate(34), n[48]
allocate(34), n[96]
deallocate(39), n[48]
main(57)
1
main(70)
deallocate(39), n[96]
- 在流上预设长字符串clang https://wandbox.org/permlink/MtHaWGuNnPkNokmn, 视觉工作室 http://rextester.com/MJKLG83660
allocate(34), n[256]
allocate(34), n[256]
deallocate(39), n[256]
main(55)
main(57)
1
main(70)
deallocate(39), n[256]
我有几个发现
- clang 和 Visual 的行为方式相同,但 gcc 对此代码存在一些严重问题。
-
std::basic_stringstream
字符串缓冲区总是增长,从不收缩
-
std::basic_stringstream
糟透了。您不能保留字符串大小或缓冲区大小,例如以防万一std::string
。自定义分配器只能按类型传递,不能按对象提供分配器。
- 为了减少分配,您必须在请求时设置大字符串,然后直到您无法成功为止,它的容量重新分配将不会发生(第二个示例)。
- 提供自定义分配器并没有多大帮助,而且它在获取结果字符串时添加了样板代码。在我的示例中,它主要用于记录分配和释放。
-
ss.str({});
不引起分配。这里小字符串优化有帮助
结论:
- 你可以安全地做
ss.str({});
正如您链接中所建议的那样,答案不会导致分配。这里小字符串优化有帮助,事实上
- 自定义分配器不是很有帮助
- 在乞讨时设置大的虚拟字符串是非常有效的邪恶黑客
- 寻找替代方案应该是更好的方法(也许是提升 - 我没有测试它)
- Point
1
你的问题表明你没有进行任何测量,你的问题是基于个人假设。