avatar

Catalog
Effective Modern C++ 笔记(8):Tweaks

Chapter 8 Tweaks

Item 41 Consider pass by value for copyable parameters that are cheap to move and always copied

  • 当需要根据参数为左值还是右值做不同的处理时,可以使用重载或者完美转发,但是它们都有各自的缺点。C++11 引入的移动语义使另一种方法成为可能:pass by value:

    c++
    1
    2
    void addName(std::string newName)
    { names.push_back(std::move(newName)); }
  • C++11 中的值传递,对于左值参数调用拷贝构造,而对于右值参数则会调用移动构造。所以整体来看相比于重载和完美转发,值传递性能上只多了一次移动的开销。

    但是注意,值传递仅建议使用于:

    • copyable 的参数。对于禁用拷贝的参数,重载只有右值版本,值传递便没有优势了(本身值传递相对于重载的优势就是后者要维护两个函数)
    • cheap to move 的参数。很好理解,毕竟值传递会多一次移动的开销。
    • always copied 的参数。这一点是说如果参数不总是被 copy(这里的 copy 是 “副本” 的含义,可以通过拷贝也可以通过移动)的话,重载或者完美转发事实上不会有任何开销,而值传递至少还要构造和析构参数。
  • 此外,通过赋值来制作参数副本的情况比通过构造要复杂得多,需要考虑诸如内存分配、优化等等问题。而且如果形参是父类,实参是子类,还容易导致 slicing problem。

Item 42 Consider emplacement instead of insertion

  • 大部分情况下,emplace 操作是比 insert 高效的(省去了临时对象的构造和析构),但是并非全部情况。有一些启发式的方法可以帮助判断哪些情况下 emplace 确实比 insert 高效:
    • 新对象被构造进容器,而非赋值进去,即添加的操作不会影响容器中原来的元素;
    • 添加操作的参数类型和容器元素的类型不同;
    • 容器允许元素重复。
  • 除了以上这些情况,emplace 操作还有一些小瑕疵:
    • 当 emplace 的参数有 new 时,在 new 出来的资源被对象接管前,会有一个真空期,如果此时抛出异常会导致内存泄漏;
    • 当 emplace 的参数类型和容器元素类型不一致时,即使容器元素类的构造声明了 explicit,emplace 操作仍能执行,但是 insert 不行(因为需要进行一次隐式转型)。

Reference

Author: Gusabary
Link: http://gusabary.cn/2020/05/28/Effective-Modern-C++-Notes/Effective-Modern-C++-Notes(8)-Tweaks/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment