如何实现移动
- 有分开的拷贝构造和移动构造函数。
- 有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
deque
list
需要指出的是,虽然 list 提供了任意位置插入新元素的灵活性,但由于每个元素的内存空 间都是单独分配、不连续,它的遍历性能比 vector 和 deque 都要低。这在很大程度上抵 消了它在插入和删除操作时不需要移动元素的理论性能优势。如果你不太需要遍历容器、又 需要在中间频繁插入或删除元素,可以考虑使用 list。 另外一个需要注意的地方是,因为某些标准算法在 list 上会导致问题,list 提供了成员函 数作为替代,包括下面几个: merge remove remove_if reverse sort unique
forward_list-单向链表
为什么会需要这么一个阉割版的 list 呢?原因是,在元素大小较小的情况下, forward_list 能节约的内存是非常可观的;在列表不长的情况下,不能反向查找也不是 个大问题。提高内存利用率,往往就能提高程序性能,更不用说在内存可能不足时的情况 了。
queue | stack
它们的特别点在于它们都不是完整的实现,而 是依赖于某个现有的容器,因而被称为容器适配器(container adaptor)。
原文链接: https://www.cnblogs.com/JohnsonQ/p/17017974.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/308881
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!