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
2void 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 不行(因为需要进行一次隐式转型)。
- 当 emplace 的参数有