EDT*_*rdy 2 c++ move move-semantics c++17
我终于感觉到我了解现代C ++中的移动语义,并且它在编写代码的方式上发生了巨大的变化。现在,我正在开发一个使用依赖注入的应用程序,并结合了我对移动语义学的新发现,但是最终我使用了std::move()太多,以至于我担心自己使用不正确。
以前,如果要在对象中注入需要复制的依赖项,则可以这样编写我的构造函数:
class NeedsCopyOfFoo
{
public:
NeedsCopyOfFoo(const Foo& foo)
: m_myFoo{foo} {}
private:
Foo m_myFoo;
};
Run Code Online (Sandbox Code Playgroud)
现在,我的课程如下所示:
class NeedsCopyOfFoo
{
public:
NeedsCopyOfFoo(Foo foo)
: m_myFoo{std::move(foo)} {}
private:
Foo m_myFoo;
};
Run Code Online (Sandbox Code Playgroud)
我的设计中有一些类需要多达三到四个类类型的依赖关系,而最终我将它们全部移走了。显然,如果构造函数的调用者无法使用右值调用构造函数,但是在构造NeedsCopyOfFoo对象之后也将不使用依赖项,那么我也需要在此使用std::move()它,以避免完全不必要的复制。
这是Modern C ++应该看起来的样子吗?鲍勃叔叔是否提到“ std::move()经常使用” 的代码味道?我是否反应过度,因为我还不习惯这种新风格?
TL; DR:如果您不希望获得完美的性能,那么
Class(const Foo& foo, const Bar& bar, ...) : m_myFoo{foo}, m_myBar{bar}, ...{...} {}
Run Code Online (Sandbox Code Playgroud)
是适合您的构造函数。它需要rvalues / lvalues,并且将花费您一个副本。它尽可能地使生活变得轻松愉快,而要过上轻松的生活有很多话要说。
对于仅一个变量,我将有一个重载集,例如
NeedsCopyOfFoo(Foo&& foo) : m_myFoo{std::move(foo)} {}
NeedsCopyOfFoo(const Foo& foo) : m_myFoo{foo} {}
Run Code Online (Sandbox Code Playgroud)
根据将哪种类型的对象传递给构造函数,此操作最多将花费一份副本或一次移动操作。这是您所能达到的最佳效果。
不幸的是,这不能很好地扩展。当您开始添加更多要以相同方式处理的参数时,过载集将平方增长。这根本不好玩,因为4参数构造函数需要16个重载才能完美。为了解决这个问题,我们可以使用转发构造函数并将其限制为SFINAE,以便仅采用所需的类型。那会给你一个像
template<typename T,
typename U,
std::enable_if_t<std::is_convertible_v<T, Foo> &&
std::is_convertible_v<U, Bar>, bool> = true>
Class(T&& foo, U&& bar) :
m_myFoo{std::forward<T>(foo)},
m_myBar{std::forward<U>(bar)} {}
Run Code Online (Sandbox Code Playgroud)
这样可以使您获得最佳性能,但是正如您所看到的那样,它非常冗长,并且需要您更多地了解要使用的C ++。
| 归档时间: |
|
| 查看次数: |
211 次 |
| 最近记录: |