我有std::stringstream ss
和std::vector<string> list
。
我希望push_back
(或emplace_back
)ss
加入list
。
如何以最佳方式避免制作ss
支持字符串的额外副本?
我的目的是立即运行ss.clear()
,因为我将重新填写它(以便稍后追加list
...)
可能的选择:
list.emplace_back(std::move(ss.str())
list.emplace_back(ss.str())
list.push_back(std::move(ss.str())
list.push_back(ss.str())
每种情况都会发生什么?每种情况下ss
会留下什么? (无论如何我都会扔掉它)
对我的不确定性做出贡献的是this topic。但事实上,我并没有将字符串流相互移动,我特别担心的是,此时能够移动构建为字符串流的字符串(可能巨大) )进入一个字符串容器的后面。显然,如果以导致某些复制或转换的方式实现str()
,这是不可避免的,但我希望能够生成能够将其填充到向量背面的代码在不断的时间。
我查看了str()
:
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>
basic_stringbuf<_CharT, _Traits, _Allocator>::str() const
{
if (__mode_ & ios_base::out)
{
if (__hm_ < this->pptr())
__hm_ = this->pptr();
return string_type(this->pbase(), __hm_, __str_.get_allocator());
}
else if (__mode_ & ios_base::in)
return string_type(this->eback(), this->egptr(), __str_.get_allocator());
return string_type(__str_.get_allocator());
}
并且进一步混淆了。
答案 0 :(得分:2)
对于这种情况,想法如下:
1)ss返回一个字符串,它是字符串流文本内部表示的 copy ,字符串有一个内部缓冲区,一个指针(这就是为什么移动对字符串有意义,尽管还有{{3} })
2)由于返回的字符串是传递给emplace的临时值,它会将构造就地移动到vector中的字符串对象,因此不会有内部缓冲区的副本(只有指针和一些整数在临时和新字符串之间交换,这很便宜)。这里差不多同样适用于push_back。
所以
所有情况都必须做几乎相同的事情(意味着他们不会复制临时字符串缓冲区)。一如既往地了解什么是更好的,但我怀疑在这种情况下有明显的区别。
答案 1 :(得分:0)
通过复制函数,返回值已默认为std :: moved。即
std::string herp() { return string("lalalalala"); }
std::string derp (herp ());
将使用derp的std :: string移动构造函数。
正如您在以下代码中所看到的,将使用移动赋值运算符。
在内部,字符串自己的operator=(&&)
将与字符串ss.str()
交换将返回
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Herp {
string internal;
public:
const Herp& operator=(const string& s)
{
cout<<"Standard initialize operator\n";
internal = s;
return *this;
}
const Herp& operator=(string&& s)
{
cout<<"Move initialize operator\n";
internal = s;
return *this;
}
};
int main()
{
Herp a;
stringstream ss;
ss<<string("abcdef");
a = ss.str();
return 0;
}
成功时间:0记忆:3428信号:0
移动初始化运算符
更多详情here。
答案 2 :(得分:0)
正如已经说过的,所有四个选项最终都做同样的事情并且是最优的 - 它们移动str()
返回的临时字符串(它是一个右值,因此push_back的&&
重载适用)到向量的后面。当您有一组要传递给emplace_back
的构造函数的参数时,value_type
会很有用。考虑:
std::vector<std::pair<std::string, std::string>> vec;
vec.push_back(std::make_pair("Hey", "You")); // a temporary pair is created here
vec.emplace_back("Hey", "You"); // arguments are forwarded to the constructor of
// pair which is constructed in place
至于您的情况,您可以做的最好的事情是使ss
成为左值并在其上调用str()
。希望stringstream
的实现足够聪明,并意识到它可以只发出内部缓冲区而不是复制它:
list.emplace_back(std::move(ss).str());