将字符串移动到字符串流中的字符串向量中

时间:2014-03-28 05:24:54

标签: c++ string c++11 stl stringstream

我有std::stringstream ssstd::vector<string> list

我希望push_back(或emplace_backss加入list

如何以最佳方式避免制作ss支持字符串的额外副本?

我的目的是立即运行ss.clear(),因为我将重新填写它(以便稍后追加list ...)

可能的选择:

  1. list.emplace_back(std::move(ss.str())
  2. list.emplace_back(ss.str())
  3. list.push_back(std::move(ss.str())
  4. list.push_back(ss.str())
  5. 每种情况都会发生什么?每种情况下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());
    } 
    

    并且进一步混淆了。

3 个答案:

答案 0 :(得分:2)

对于这种情况,想法如下:
1)ss返回一个字符串,它是字符串流文本内部表示的 copy ,字符串有一个内部缓冲区,一个指针(这就是为什么移动对字符串有意义,尽管还有{{3} })
2)由于返回的字符串是传递给emplace的临时值,它会将构造就地移动到vector中的字符串对象,因此不会有内部缓冲区的副本(只有指针和一些整数在临时和新字符串之间交换,这很便宜)。这里差不多同样适用于push_back。

所以

  1. list.emplace_back(标准::移动(ss.str())
  2. list.emplace_back(ss.str())
  3. list.push_back(标准::移动(ss.str())
  4. list.push_back(ss.str())
  5. 所有情况都必须做几乎相同的事情(意味着他们不会复制临时字符串缓冲区)。一如既往地了解什么是更好的,但我怀疑在这种情况下有明显的区别。

答案 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());