传递值和移动,或两种方法
Pass by value and move, or two methods
假设我有以下类,它有一个方法set_value
。哪种实施方式更好?
class S {
public:
// a set_value method
private:
Some_type value;
};
传递值,然后移动
void S::set_value(Some_type value)
{
this->value = std::move(value);
}
定义两个重载方法
void S::set_value(const Some_type& value)
{
this->value = value;
}
void S::set_value(Some_type&& value)
{
this->value = std::move(value);
}
第一种方法只需要定义一种方法,而第二种方法需要定义两种方法。
然而,第一种方法似乎效率较低:
- 根据传递的参数复制/移动参数的构造函数
- 移动分配
- 参数的析构函数
而对于第二种方法,只执行一个分配操作。
- 根据调用的重载方法复制/移动赋值
那么,哪种实现方式更好呢?或者这有关系吗?
还有一个问题:下面的代码是否等效于第二种方法中的两个重载方法?
template <class T>
void S::set_value(T&& value)
{
this->value = std::forward<T>(value);
}
编译器可以自由地消除(优化掉)副本,即使这样做会有副作用。因此,传递值和移动结果实际上为您提供了两种方法解决方案的所有性能优势,同时只为您提供一个代码路径来维护。你绝对应该更喜欢通过价值传递。
这里有一个例子来证明这一点:
#include <iostream>
struct XYZ {
XYZ() { std::cout << "constructed" << std::endl; }
XYZ(const XYZ&) {
std::cout << "copy constructed" << std::endl;
}
XYZ(XYZ&&) noexcept {
try {
std::cout << "move constructed" << std::endl;
}
catch(...) {
}
}
XYZ& operator=(const XYZ&) {
std::cout << "assigned" << std::endl;
return *this;
}
XYZ& operator=(XYZ&&) {
std::cout << "move-assigned" << std::endl;
return *this;
}
};
struct holder {
holder(XYZ xyz) : _xyz(std::move(xyz)) {}
void set_value(XYZ xyz) { _xyz = std::move(xyz); }
void set_value_by_const_ref(const XYZ& xyz) { _xyz = xyz; }
XYZ _xyz;
};
using namespace std;
auto main() -> int
{
cout << "** create named source for later use **" << endl;
XYZ xyz2{};
cout << "n**initial construction**" << std::endl;
holder h { XYZ() };
cout << "n**set_value()**" << endl;
h.set_value(XYZ());
cout << "n**set_value_by_const_ref() with nameless temporary**" << endl;
h.set_value_by_const_ref(XYZ());
cout << "n**set_value() with named source**" << endl;
h.set_value(xyz2);
cout << "n**set_value_by_const_ref() with named source**" << endl;
h.set_value_by_const_ref(xyz2);
return 0;
}
预期输出:
** create named source for later use **
constructed
**initial construction**
constructed
move constructed
**set_value()**
constructed
move-assigned
**set_value_by_const_ref() with nameless temporary**
constructed
assigned
**set_value() with named source**
copy constructed
move-assigned
**set_value_by_const_ref() with named source**
assigned
请注意,在复制/移动版本中没有任何冗余副本,但在使用匿名临时调用set_value_by_const_ref()
时有冗余副本分配。我注意到最后一种情况明显提高了效率。我认为(a)这是现实中的一个角落,(b)优化器可以处理它。
我的命令行:
c++ -o move -std=c++1y -stdlib=libc++ -O3 move.cpp
相关文章:
- 定义类模板构造函数的两种方法之间的区别
- 初始化类的两种方法?
- 在没有堆的情况下用两种方法构造对象
- 解决虚拟方法的歧义继承的两种方法
- 这两种方法有什么区别?
- 确保派生的类实现至少是来自抽象类(C )的两种方法之一
- 动态分配一维结构数组:两种方法
- 初始化`rand()的两种方法
- 分配std :: vector元素的两种方法
- 同步QT中两种方法的螺纹执行
- 这两种方法有什么区别
- 关于链表,这两种方法有什么不同?C++中的1个自变量与2个自变量
- 我可以将这两种方法/函数合二为一吗?
- 如何减少googletest的详细程度(覆盖默认侦听器的两种方法)
- 就百分比而言,这两种方法之间的平均性能差异有多大
- 在C++中抛出异常的两种方法(不使用堆)
- 将两种方法组合在一起
- 以下两种方法在 c++ 中有什么区别
- 使用两种方法重写<<运算符
- 函数指针实现的两种方法之间的差异