可移动但不可复制的对象:按值传递还是按引用传递?
Movable but non-copyable objects: passing by value vs by reference?
仅考虑可移动但不可复制的对象(例如,std::thread
或std::unique_ptr
) , 我想通过将此类对象作为参数传递给构造函数来 转移此类对象包含的资源的所有权 。我正在比较两种方法:构造函数按值与按右值引用.
作为 std::thread
的示例,请考虑以下 class Value
,其构造函数采用 std::thread
值 :
#include <thread>
#include <utility>
struct Value {
Value(std::thread th): th_(std::move(th)) {}
std::thread th_;
};
所有权从参数对象转移到参数对象,th
,最后转移到数据成员对象,th_
。
考虑一个类似的 class、Reference
,其构造函数在本例中采用 std::thread
by rvalue reference:
struct Reference {
Reference(std::thread&& th): th_(std::move(th)) {}
std::thread th_;
};
在这种情况下,所有权从参数直接转移到数据成员对象,th_
。
据我了解,在按值传递的情况下,参数对象和数据成员对象都是移动构造的,而对于按引用传递的情况,只有数据成员是移动构造的建。总而言之,后一种方法似乎更好,因为它只需要一次移动操作,因此效率更高。
然而,是否有任何理由更喜欢按值传递方法而不是按引用传递方法?
按值传递是自我记录的方式,而按引用传递则不是。 reader 立即可以看出:
- 构造函数将无条件地取得由 move-only 类型表示的资源的所有权;
- 如果 move 构造因任何原因抛出异常而失败,则由调用者负责处理; (*)
- 如果构造函数通过抛出异常退出,资源将被处理掉。
(同样,在实现中也很难或不可能出现错误导致上述假设不成立。)
当然,最终这些收益是否超过额外移动构造的成本的问题是基于意见的。
(*) 当然,这不适用于构造函数内部执行的移动,即从参数到成员的。但是,这里的重点是调用者可以控制 他们的 对象发生的事情:要么将其移入构造函数参数,要么,如果该步骤出现任何故障,调用者可以做损害控制(可能保留价值)。
仅考虑可移动但不可复制的对象(例如,std::thread
或std::unique_ptr
) , 我想通过将此类对象作为参数传递给构造函数来 转移此类对象包含的资源的所有权 。我正在比较两种方法:构造函数按值与按右值引用.
作为 std::thread
的示例,请考虑以下 class Value
,其构造函数采用 std::thread
值 :
#include <thread>
#include <utility>
struct Value {
Value(std::thread th): th_(std::move(th)) {}
std::thread th_;
};
所有权从参数对象转移到参数对象,th
,最后转移到数据成员对象,th_
。
考虑一个类似的 class、Reference
,其构造函数在本例中采用 std::thread
by rvalue reference:
struct Reference {
Reference(std::thread&& th): th_(std::move(th)) {}
std::thread th_;
};
在这种情况下,所有权从参数直接转移到数据成员对象,th_
。
据我了解,在按值传递的情况下,参数对象和数据成员对象都是移动构造的,而对于按引用传递的情况,只有数据成员是移动构造的建。总而言之,后一种方法似乎更好,因为它只需要一次移动操作,因此效率更高。
然而,是否有任何理由更喜欢按值传递方法而不是按引用传递方法?
按值传递是自我记录的方式,而按引用传递则不是。 reader 立即可以看出:
- 构造函数将无条件地取得由 move-only 类型表示的资源的所有权;
- 如果 move 构造因任何原因抛出异常而失败,则由调用者负责处理; (*)
- 如果构造函数通过抛出异常退出,资源将被处理掉。
(同样,在实现中也很难或不可能出现错误导致上述假设不成立。)
当然,最终这些收益是否超过额外移动构造的成本的问题是基于意见的。
(*) 当然,这不适用于构造函数内部执行的移动,即从参数到成员的。但是,这里的重点是调用者可以控制 他们的 对象发生的事情:要么将其移入构造函数参数,要么,如果该步骤出现任何故障,调用者可以做损害控制(可能保留价值)。