C++ | 2-移动

如何实现移动

  • 有分开的拷贝构造和移动构造函数。
  • 有swap成员函数,支持和另外一个对象快速交换成员。
  • 你的对象的名空间下,应当有一个全局的 swap 函数,调用成员函数 swap 来实现交换。支持这种用法会方便别人(包括你自己在将来)在其他对象里包含你的对象,并快速实现它们的 swap 函数。
  • 实现通用的 operator=。
  • 上面各个函数如果不抛异常的话,应当标为 noexcept。这对移动构造函数尤为重要。

移动构造函数应当从另一个对象获取资源,清空其资源,并将其 置为一个可析构的状态。

对传递左值和右值都 有效,规避if (&rhs != this) 这样的判断小技巧:

smart_ptr&
operator=(smart_ptr rhs) noexcept
{
rhs.swap(*this);
return *this;
}

(初始化参数rhs的时候,根据传入的是左值还是右值去匹配初始化)

不要返回本地变量的引用(C++11开始)

从 C++11 开始,返回值优化仍可以发生,但在没有返回值优化的情况下,编译器将 试图把本地对象移动出去,而不是拷贝出去。这一行为不需要程序员手工用 std::move 进 行干预——使用std::move 对于移动行为没有帮助,反而会影响返回值优化。

引用坍缩和完美转发

对于 template foo(T&&) 这样的代码,如果传递过去的参数是左值,T的推导结果是左值引用;如果传递过去的参数是右值,T 的推导结果是参数的类型本身(右值引用变量仍然会匹配到左值引用上)。

如果 T 是左值引用,那 T&& 的结果仍然是左值引用——即 type& && 坍缩成了 type&。 如果 T 是一个实际类型,那 T&& 的结果自然就是一个右值引用。

应对策略:std::forward

template <typename T>
void bar(T&& s)
{
foo(std::forward<T>(s));
}

因为在 T 是模板参数时,T&& 的作用主要是保持值类别进行转发,它有个名字就叫“转发 引用”(forwarding reference)。因为既可以是左值引用,也可以是右值引用,它也曾 经被叫做“万能引用”(universal reference)。

容器的影响

如果元素类型没有提供一个保证不抛异常的移动构造函 数,vector 通常会使用拷贝构造函数。因此,对于拷贝代价较高的自定义元素类型,我们 应当定义移动构造函数,并标其为 noexcept,或只在容器中放置对象的智能指针。

vector

C++ | 2-移动

 

 

 

deque

C++ | 2-移动

 

 

list

C++ | 2-移动

 

 需要指出的是,虽然 list 提供了任意位置插入新元素的灵活性,但由于每个元素的内存空 间都是单独分配、不连续,它的遍历性能比 vector 和 deque 都要低。这在很大程度上抵 消了它在插入和删除操作时不需要移动元素的理论性能优势。如果你不太需要遍历容器、又 需要在中间频繁插入或删除元素,可以考虑使用 list。 另外一个需要注意的地方是,因为某些标准算法在 list 上会导致问题,list 提供了成员函 数作为替代,包括下面几个:  merge remove remove_if  reverse sort unique

forward_list-单向链表

C++ | 2-移动

 

 为什么会需要这么一个阉割版的 list 呢?原因是,在元素大小较小的情况下, forward_list 能节约的内存是非常可观的;在列表不长的情况下,不能反向查找也不是 个大问题。提高内存利用率,往往就能提高程序性能,更不用说在内存可能不足时的情况 了。

queue | stack

 它们的特别点在于它们都不是完整的实现,而 是依赖于某个现有的容器,因而被称为容器适配器(container adaptor)。

原文链接: https://www.cnblogs.com/JohnsonQ/p/17017974.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++ | 2-移动

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/308881

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 上午10:23
下一篇 2023年2月16日 上午10:25

相关推荐