gpt4 book ai didi

c++ - 对右值引用 vector::push_back 函数如何提高效率感到困惑

转载 作者:太空狗 更新时间:2023-10-29 20:09:44 44 4
gpt4 key购买 nike

从 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));) 将触发 vector 构造一个 std::string 类型变量并将其附加到 vector 。

因此,实际上在两个 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));

对比

    this->_Getal().construct(_Unfancy(this->_Mylast()),
_Val);

现在forward<value_type>实际上调用std::movestd::string 上.

在一种情况下,我们构造一个 std::string通过 std::string const& , 在另一个由std::string && .

因此,要了解差异,我们必须检查这两个不同的构造函数的作用。

std::string通常用 SBO(小缓冲区优化)实现。如果字符串很短(十几个字符左右),则该字符串存储在 within std::string 中。 .

如果它更长,而不是 std::string存储指向它的指针。

如果您激活了 SBO,则 move 和 copy 都将字节复制过来。然后 Move 可能会清除源。

std::string(std::string const&)在非 SBO 的情况下进行分配并复制包含字符的缓冲区。

std::string(std::string &&)在非 SBO 的情况下,将指针移至目标对象,并清空源对象。没有内存分配发生,零字节被复制。

这就是push_back(&&)重载提供。

关于c++ - 对右值引用 vector::push_back 函数如何提高效率感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43528928/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com