需要按值传递的条件:对于可复制的、在移动成本低廉的并且一定会被复制的形参,按值传递可能会和按引用传递的具备相近的效率,并且可能生成更少量的目标代码。
条件解读和示例代码如下:
- 按值传递的好处:
- 1,只需要考虑按值传递 (相对于重载版本只要撰写单个函数;相对于万能引用版本可以避免万能引用带来的一系列问题)【效率可能没有剩余两者高】;
- 2,仅针对可复制的形参,才考虑按值传递(如果形参是只移动类型,那么重载版本就只需要一个接受右值的重载版本,失去了按值传递的好处);
- 3,按值传递仅在移动成本低廉的情况下,才值得考虑(因为按值传递,相对于重载和万能引用版本会多一次额外的移动操作,如果移动操作成本高,那么移动就和复制没有区别了);
- 4,应该只针对移动会被复制的形参菜考虑按值传递。
- 因为对于构造来实施形参复制的函数,使用按值传递,无论传入的是左值还是右值,都会招致一次额外移动所带来的成本;
- 对于采用赋值来实施赋形参复制的,可能会导致额外的内存分配和回收的成本(例如,动态分配中存值的一部分形参类型,例如
std::string
和std::vector
)
//版本1:左右值重载 class Widget{ public: void addName(const std::string& newName){ names.push_back(newName); } void addName(std::string&& newName){ names.push_back(newName); } private: std::vector<std::string> names; }; //版本2:万能引用 class Wiget{ public: template<class T> void addName(T&& newName){ names.push_back(std::forward<T>(newName)); } private: std::vector<std::string> names; }; //版本3:按值传递 class Widget{ public: void addName(std::string newName){ names.push_back(std::move(newName)); } private: std::vector<std::string> names; };
结论就是总是采用重载或者万能引用,而非按值传递,除非确定按值传递能够为所需的形参类型生成可接受效率的代码。