gal*_*tte 27 c++ ostringstream move-semantics c++11
如果我构造一个由空格分隔的浮点值列表组成的字符串,使用std::ostringstream:
std::ostringstream ss;
unsigned int s = floatData.size();
for(unsigned int i=0;i<s;i++)
{
ss << floatData[i] << " ";
}
Run Code Online (Sandbox Code Playgroud)
然后我得到一个结果std::string:
std::string textValues(ss.str());
Run Code Online (Sandbox Code Playgroud)
但是,这将导致不必要的字符串内容的深层副本,因为ss将不再使用.
有没有办法在不复制整个内容的情况下构造字符串?
Nic*_*asM 17
现在可以使用 C++20 实现这一点,语法如下:
const std::string s = std::move(ss).str();
Run Code Online (Sandbox Code Playgroud)
这是可能的,因为该类std::ostringstream现在具有str()右值引用限定的重载:
basic_string<charT, traits, Allocator> str() &&; // since C++20
Run Code Online (Sandbox Code Playgroud)
这是在P0408修订版 7 中添加的,并被C++20 采用。
这正是 @MarcGlisse 在 2014 年 10 月的一篇有先见之明的评论中建议的方法。
Cub*_*bbi 11
std::ostringstream提供没有公共接口来访问其内存缓冲区,除非它不支持pubsetbuf(但即使这样你的缓冲区是固定大小的,请参阅cppreference示例)
如果要折磨某些字符串流,可以使用受保护的接口访问缓冲区:
#include <iostream>
#include <sstream>
#include <vector>
struct my_stringbuf : std::stringbuf {
const char* my_str() const { return pbase(); } // pptr might be useful too
};
int main()
{
std::vector<float> v = {1.1, -3.4, 1/7.0};
my_stringbuf buf;
std::ostream ss(&buf);
for(unsigned int i=0; i < v.size(); ++i)
ss << v[i] << ' ';
ss << std::ends;
std::cout << buf.my_str() << '\n';
}
Run Code Online (Sandbox Code Playgroud)
直接访问自动调整大小的输出流缓冲区的标准C++方法由std::ostrstreamC++ 98中提供,但仍然是标准的C++ 14和计数.
#include <iostream>
#include <strstream>
#include <vector>
int main()
{
std::vector<float> v = {1.1, -3.4, 1/7.0};
std::ostrstream ss;
for(unsigned int i=0; i < v.size(); ++i)
ss << v[i] << ' ';
ss << std::ends;
const char* buffer = ss.str(); // direct access!
std::cout << buffer << '\n';
ss.freeze(false); // abomination
}
Run Code Online (Sandbox Code Playgroud)
但是,我认为最干净(也是最快)的解决方案是boost.karma
#include <iostream>
#include <string>
#include <vector>
#include <boost/spirit/include/karma.hpp>
namespace karma = boost::spirit::karma;
int main()
{
std::vector<float> v = {1.1, -3.4, 1/7.0};
std::string s;
karma::generate(back_inserter(s), karma::double_ % ' ', v);
std::cout << s << '\n'; // here's your string
}
Run Code Online (Sandbox Code Playgroud)
+1 为@Cubbi 的 Boost Karma 和“创建您自己的streambuf不制作副本的派生类型,并将其提供给 a 的构造函数”的建议basic_istream<>。.
但是,缺少一个更通用的答案,它介于两者之间。它使用 Boost Iostreams:
using string_buf = bio::stream_buffer<bio::back_insert_device<std::string> >;
Run Code Online (Sandbox Code Playgroud)
这是一个演示程序:
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream_buffer.hpp>
namespace bio = boost::iostreams;
using string_buf = bio::stream_buffer<bio::back_insert_device<std::string> >;
// any code that uses ostream
void foo(std::ostream& os) {
os << "Hello world "
<< std::hex << std::showbase << 42
<< " " << std::boolalpha << (1==1) << "\n";
}
#include <iostream>
int main() {
std::string output;
output.reserve(100); // optionally optimize if you know roughly how large output is gonna, or know what minimal size it will require
{
string_buf buf(output);
std::ostream os(&buf);
foo(os);
}
std::cout << "Output contains: " << output;
}
Run Code Online (Sandbox Code Playgroud)
请注意,您可以轻松地替换
std::stringwithstd::wstring或std::vector<char>等。
更好的是,您可以将它与array_sink设备一起使用并拥有一个固定大小的缓冲区。这样您就可以避免使用 Iostreams 代码进行任何缓冲区分配!
#include <boost/iostreams/device/array.hpp>
using array_buf = bio::stream_buffer<bio::basic_array<char>>;
// ...
int main() {
char output[100] = {0};
{
array_buf buf(output);
std::ostream os(&buf);
foo(os);
}
std::cout << "Output contains: " << output;
}
Run Code Online (Sandbox Code Playgroud)
两个程序都打印:
Output contains: Hello world 0x2a true
Run Code Online (Sandbox Code Playgroud)