c – 由于右值参考向量:: push_back函数如何提高效率而感到困惑
作者:互联网
在cppreference.com上,我找到了一个关于使用std :: move的简单示例:
std::string str = "Hello";
std::vector<std::string> v;
// uses the push_back(const T&) overload, which means
// we'll incur the cost of copying str
v.push_back(str); // First push_back
std::cout << "After copy, str is \"" << str << "\"\n";
// uses the rvalue reference push_back(T&&) overload,
// which means no strings will be copied; instead, the contents
// of str will be moved into the vector. This is less
// expensive, but also means str might now be empty.
v.push_back(std::move(str)); // Second push_back
评论说避免了字符串拷贝.
第一个push_back将调用:void push_back(const value_type& _Val)
第二个push_back将调用:void push_back(value_type&& _Val)
我检查了两个函数的实现代码:
void push_back(const value_type& _Val)
{ // insert element at end
if (_Inside(_STD addressof(_Val)))
{ // push back an element
size_type _Idx = _STD addressof(_Val) - _Unfancy(this->_Myfirst());
if (this->_Mylast() == this->_Myend())
_Reserve(1);
_Orphan_range(this->_Mylast(), this->_Mylast());
this->_Getal().construct(_Unfancy(this->_Mylast()),
this->_Myfirst()[_Idx]);
++this->_Mylast();
}
else
{ // push back a non-element
if (this->_Mylast() == this->_Myend())
_Reserve(1);
_Orphan_range(this->_Mylast(), this->_Mylast());
this->_Getal().construct(_Unfancy(this->_Mylast()),
_Val);
++this->_Mylast();
}
}
和
void push_back(value_type&& _Val)
{ // insert by moving into element at end
if (_Inside(_STD addressof(_Val)))
{ // push back an element
size_type _Idx = _STD addressof(_Val) - _Unfancy(this->_Myfirst());
if (this->_Mylast() == this->_Myend())
_Reserve(1);
_Orphan_range(this->_Mylast(), this->_Mylast());
this->_Getal().construct(_Unfancy(this->_Mylast()),
_STD forward<value_type>(this->_Myfirst()[_Idx]));
++this->_Mylast();
}
else
{ // push back a non-element
if (this->_Mylast() == this->_Myend())
_Reserve(1);
_Orphan_range(this->_Mylast(), this->_Mylast());
this->_Getal().construct(_Unfancy(this->_Mylast()),
_STD forward<value_type>(_Val));
++this->_Mylast();
}
}
所以,根据我的理解,第一个push_back(v.push_back(str);)和第二个push_back(v.push_back(std :: move(str));)都会触发向量来构造一个std :: string类型的变量并将其附加到矢量.
因此,实际上在两个push_back调用中,都没有复制字符串.并且,对于两个push_back,费用是相同的,因为两个调用基本上做同样的事情,除了第二个push_back将使str输入为空.
至于效率,我能想到的唯一区别是第二个push_back不会调用delete [] cstring;在std :: string的析构函数中,它使第二个push_back调用更有效率.
不确定我的理解是否正确.非常感谢!
解决方法:
区别在于:
this->_Getal().construct(_Unfancy(this->_Mylast()),
_STD forward<value_type>(_Val));
VS
this->_Getal().construct(_Unfancy(this->_Mylast()),
_Val);
现在转发< value_type>实际上在std :: string上调用std :: move.
在一种情况下,我们用std :: string const&和std :: string&&来构造一个std :: string.
所以为了看到差异,我们必须检查这两个不同构造函数的作用.
std :: string通常用SBO实现(小缓冲区优化).如果字符串很短(十几个字符),则字符串存储在std :: string中.
如果它更长,则std :: string存储指向它的指针.
如果SBO处于活动状态,则移动和复制将字节复制过来.然后移动可以清除源.
在非SBO的情况下,std :: string(std :: string const&)执行分配并复制包含字符的缓冲区.
在非SBO的情况下,std :: string(std :: string&&)将指针移动到目标对象,并清空源对象.不进行内存分配,并复制零字节.
这就是push_back(&& amp;)重载提供的内容.
标签:c,c11,move,vector,rvalue-reference 来源: https://codeday.me/bug/20190727/1552235.html