C++ 编译字符串并将其作为向量返回

C++ 编译字符串并将其作为向量返回,c++,string,stl,stringstream,C++,String,Stl,Stringstream,我的服务器收到一些请求,编译响应并将其发回。有时响应是一个文件,有时是HTML。因此,我用以下方式定义响应: class ResponseData { public: bool operator== (const ResponseData & param) const { return id == param.id; } public: RequestIdType id; RequestType type; std::vector<char>

我的服务器收到一些请求,编译响应并将其发回。有时响应是一个文件,有时是HTML。因此,我用以下方式定义响应:

class ResponseData
{

public:
    bool operator== (const ResponseData & param) const { return id == param.id; }

public:
    RequestIdType id;
    RequestType type;
    std::vector<char> data;
};

在我看来,将
buffer
复制到字符串中,然后将其附加到向量中并不是一个好主意。我如何才能更有效地执行此操作?

只需将
stringstream
用于所有操作。演示如何直接从
stringstream
复制

std::stringstream buffer;

buffer << RESPONSE_HEADER;

for( auto param : request->paramsMap )
{
    buffer << "<tr><td>" << param.first << "</td><td>" << param.second << "</td></tr>\n";
    DEBUG_LOG_F << "<tr><td>" << param.first << "</td><td>" << param.second << "</td></tr>\n";
}

buffer << RESPONSE_FOOTER;

return sstreamToVector(buffer);
std::stringstream缓冲区;
缓冲区参数(SMAP)
{

buffer您可以使用
std::istreambuf\u迭代器
将字符直接从
stringstream
复制到向量,如下所示:

std::vector<char> sstreamToVector(std::stringstream& src)
{
    // make sure that "get" position is at the beginning and "put" is at the end of the stream
    src.seekg(0);
    src.seekp(0, std::ios::end);

    std::vector<char> dst;
    dst.reserve(src.tellp());
    std::copy(std::istreambuf_iterator<char>(src),
              std::istreambuf_iterator<char>(),
              std::back_inserter(dst));
    return dst;
}
std::vector sstreamToVector(std::stringstream&src)
{
//确保“get”位置在流的开头,“put”位置在流的末尾
src.seekg(0);
src.seekp(0,std::ios::end);
std::向量dst;
dst.reserve(src.tellp());
std::copy(std::istreambuf_迭代器(src),
std::istreambuf_迭代器(),
标准:背向插入器(dst);
返回dst;
}

str.tellp()
返回写入流的字符数(
p
代表“放置区域”),因此它可以用来在缓冲区中分配足够的空间。

据我所知,您试图避免的是容器之间的
char
s移动。在这种简单的情况下,直接转储
result
中的所有内容并不难:

auto result = accumulate(cbegin(request->paramsMap), cend(request->paramsMap), vector<char>{ '<', 't', 'r', '>', '<', '/', 't', 'r', '>' }, [](auto& init, const auto& i) {
    const char start[] = { '<', 't', 'r', '>', '<', 't', 'd', '>' };
    const char middle[] = { '<', '/', 't', 'd', '>', '<', 't', 'd', '>' };
    const char finish[] = { '<', '/', 't', 'd', '>', '<', '/', 't', 'r', '>' };

    init.insert(prev(cend(init), 5U), cbegin(start), cend(start));
    init.insert(prev(cend(init), 5U), i.first, next(i.first, strlen(i.first)));
    init.insert(prev(cend(init), 5U), cbegin(middle), cend(middle));
    init.insert(prev(cend(init), 5U), i.second, next(i.second, strlen(i.second)));
    init.insert(prev(cend(init), 5U), cbegin(finish), cend(finsh));
    return init;
} );

copy(cbegin(result), cend(result), ostream_iterator<char>{ DEBUG_LOG_F });
result.insert(cbegin(result), RESPONSE_HEADER, next(RESPONSE_HEADER, strlen(RESPONSE_HEADER)));
result.insert(cend(result), RESPONSE_FOOTER, next(RESPONSE_FOOTER, strlen(RESPONSE_FOOTER)));
return result;
auto result=accumulate(cbegin(请求->参数映射)、cend(请求->参数映射)、向量{''、'}、[](自动初始化、常量自动和i){
常量字符开始[]={'',''};
常量字符中间[]={'',''};
const char finish[]={'',''};
初始插入(上一个(cend(初始),5U),cbegin(开始),cend(开始));
初始插入(上一个(cend(初始),5U),i.first,下一个(i.first,strlen(i.first));
初始插入(上一个(初始),5U,cbegin(中间),中间);
初始插入(上一个(cend(初始),5U),一秒,下一个(一秒,斯特伦(一秒));
初始插入(上一个(初始),5U,cbegin(精加工),中心(finsh));
返回init;
} );
复制(cbegin(结果)、cend(结果)、ostream_迭代器{DEBUG_LOG_F});
结果.插入(cbegin(结果),RESPONSE_头,next(RESPONSE_头,strlen(RESPONSE_头));
结果.插入(cend(结果)、应答页脚、next(应答页脚、strlen(应答页脚));
返回结果;


我建议进行以下优化。1.事先在结果中为所有内容保留空间。2.从缓冲区获取streambuf实例,然后使用其sgetn函数直接填充结果向量。您是否打算使用两个深度的
生成结果?@NishantSingh,看起来您错过了几个lines@Caleth,谢谢。当然,没有。但主要问题是如何有效地将stringstream复制到vector@Yurasry我已经更新了comment@NishantSingh.你不认为
std::string str=buffer.str()
会减慢程序的速度吗?如果我这样做,我会再次实例化内存,只是为了从
stringstream
获取数据unnecessary@Yura是的。但是这更容易理解,只是不要进行字符串转换,在填充stringstream之后,获取streambuf实例,然后使用其sgetn函数填充re不管怎样,joe_chip提供的解决方案似乎也在做同样的事情,所以应该是相同的efficient@Caleth但我认为C++写作应该注重实效性。至少我试着学习方法。这就是问题。无论如何,谢谢你。ideas@Yura:那是因为你做了一个新的缓冲区。诀窍是直接从原始版本中复制。Joe向您展示了如何进行。编译器如何在这里防止这种情况?(提示:不会!)您的XML斜杠是向后的,您没有逃脱错误的反斜杠。@LightnessRacesinOrbit我曾希望编译器能够识别这里的
result
的结构,并移动OP的
缓冲区
响应页眉
响应页脚
的内容,但甚至可以将其输入出来我太乐观了…我会编辑。我是说你说的优化原始代码,但那也是!@LightnessRacesinOrbit是的,真的,
accumulate
现在确实在内部进行复制。不过,如果在C++20中解决这个问题…我可能会寻求结束和开始,首先,只是为了安全,否则@LightnessRacesinOrbit很好,将其放入单独的函数中时,应该执行(+可能在末尾恢复它们)哦,恢复是个好主意。有些人会说,应该遵守函数外部的光标状态,并且应该在“消耗”所有字节后才结束.但由于我们从未真正从stringstream中消费任何东西(至少不是破坏性的),所以只要您记录您的选择,这并不重要。
auto result = accumulate(cbegin(request->paramsMap), cend(request->paramsMap), vector<char>{ '<', 't', 'r', '>', '<', '/', 't', 'r', '>' }, [](auto& init, const auto& i) {
    const char start[] = { '<', 't', 'r', '>', '<', 't', 'd', '>' };
    const char middle[] = { '<', '/', 't', 'd', '>', '<', 't', 'd', '>' };
    const char finish[] = { '<', '/', 't', 'd', '>', '<', '/', 't', 'r', '>' };

    init.insert(prev(cend(init), 5U), cbegin(start), cend(start));
    init.insert(prev(cend(init), 5U), i.first, next(i.first, strlen(i.first)));
    init.insert(prev(cend(init), 5U), cbegin(middle), cend(middle));
    init.insert(prev(cend(init), 5U), i.second, next(i.second, strlen(i.second)));
    init.insert(prev(cend(init), 5U), cbegin(finish), cend(finsh));
    return init;
} );

copy(cbegin(result), cend(result), ostream_iterator<char>{ DEBUG_LOG_F });
result.insert(cbegin(result), RESPONSE_HEADER, next(RESPONSE_HEADER, strlen(RESPONSE_HEADER)));
result.insert(cend(result), RESPONSE_FOOTER, next(RESPONSE_FOOTER, strlen(RESPONSE_FOOTER)));
return result;