将移出参数的最佳做法

Best practice for will-move-from parameters

本文关键字:最佳 移出 参数      更新时间:2023-10-16

根据核心准则:

F.18:对于"will-move-from"参数,通过X&&&和std::move参数传递

示例为:

void sink(vector<int>&& v) {   // sink takes ownership of whatever the argument owned
// usually there might be const accesses of v here
store_somewhere(std::move(v));
// usually no more use of v here; it is moved-from
}

我注意到我倾向于对所有对象使用智能指针,除了廉价复制的对象(我几乎总是只考虑原语(。所以我几乎总是使用以下准则:

void sink(std::unique_ptr<OtherThanPrimitive> p) {
// use p ... possibly std::move(p) onward somewhere else
}   // p gets destroyed

我开始考虑我是否使用最佳实践。我能想到的第一种方法的优点是强制函数的调用者显式 std::move,它使代码更干净。在第二种方法中,移动构造函数将被调用两次,但对于智能指针来说,这不是一个很大的成本。考虑到上述情况,我开始考虑改变我的习惯,始终将第一种方法用于我确信支持移动的集合(因此大多数 STL 集合(。自定义对象的第二种方法(我假设考虑为类编写自定义移动构造函数的成本超过了可读性的好处(。是否有任何最佳实践可以涵盖这一点?您通常采用什么方法?我的理由中遗漏了什么吗?

我认为第一种方法的优点是强制函数的调用者显式 std::move,它使代码更干净。在第二种方法中,移动构造函数将被调用两次,但对于智能指针来说,这不是一个很大的成本。

void sink(T&&)void sink(T)之间:两者都需要仅移动类型或调用移动构造函数的std::move。第二种形式也可以复制,给定一个可复制的左值参数。如果T复制不便宜,默默地获得副本可能是一个缺点。与第一种方法相比,第二种形式即使与仅移动类型一起使用,也会在函数参数中具有额外的移动。如果T移动起来不便宜,那可能是一个缺点。当移动到数据成员中时,或以其他方式在逻辑上复制参数时,第二种形式允许一个重载同时接受 T&& 和 const T& 参数,而不是为每个参数设置一个重载,然后对 N 个参数进行 2^N 个重载。

但是,第二种形式无条件地从论点中移出。第一个可以有条件地离开参数,或者根本不离开参数。呼叫者无法分辨(不好! 第二种形式提供了更清晰的意图表达。

请注意,问题 526 有一个不错的小助手函数copy您可以将其与第一个表单一起使用,用于不太便宜的可复制类型,以明确复制。使用该帮助程序,您可以默认使用最少的移动次数进行移动,并选择加入显式复制。签名提供的意图仍然不如第二种形式那么清晰。

考虑到上述情况,我开始考虑改变我的习惯,始终将第一种方法用于我确信支持移动的集合(因此大多数 STL 集合(。自定义对象的第二种方法

我不认为自定义对象与支持移动的集合是正确的区别。如果T不可移动,则应const T&T参数(如果需要副本(。在这种情况下使用第一种形式是没有意义的。

如果T是可移动的,根据经验,请使用核心准则。使用第一种形式。如果T是廉价的,请使用第二种形式。

我假设考虑为类编写自定义移动构造函数的成本超过了可读性的利润

不需要为大多数类编写自定义移动构造函数。存储由某些东西拥有。这需要一个自定义移动构造函数。指向存储的内部簿记会产生对自定义移动构造函数的需求。所以,容器。如果你正在编写一个容器,用于与提供的类型一起通用,如果它可以更有效,则可能应该编写一个移动构造函数。否则可能会更令人惊讶。