如果我有一个管理一些动态内存的类(例如一个矢量类型的类),它已经有一个移动构造函数,它是否有意义提供一个移动感知的重载函数,或者将移动构造函数照顾它?
例如,我应该用Class&&
变体重载其中哪一个(如果有的话):
// the move-aware overload for all of these would be
// void FuncX(Class&&);
void Func1(Class);
void Func3(Class&); // doesn't make a local copy
void Func4(Class&); // makes a local copy
void Func5(Class const);
void Func7(Class const&); // doesn't make a local copy
void Func8(Class const&); // makes a local copy
是否因为我没有提供移动感知变体而失去了优化机会?
Func1
和Func5
具有相同的签名,并且已经具有"move-aware",因为它们可以用左值或右值调用,并且参数可以在传递右值时构造。
Func3
和Func4
目前不能用右值调用,用Func(Class&&)
重载它们将是语义上的重大变化,而不仅仅是优化。
Func7
已经可以用右值调用了,没有什么可以通过复制或移动来初始化的,重载它是没有意义的。
Func8
可以用右值调用,但执行复制,将该函数更改为Func8(Class)
将使用复制或移动来初始化参数,这取决于它是用左值还是右值调用。或者,用Func8(Class&&)
重载它也允许您在传递右值时避免复制,但是现在您有两个函数需要维护。
首先,当然,您不应该为移动感知而烦恼重载,直到分析器显示它是必要的;这是额外的复杂性,它不应该被引入,除非是必要的。
然而,假设分析器确实显示复制是显著的开销:
Func1
(和具有相同签名的Func5
): This违反了大多数编码准则(要求传递类对象)通过引用const);如果使用此签名,则为可能是因为您需要参数的唯一副本。移动语义会给你一个唯一的副本,所以它们可能是合适。
Func2
和Func3
暗示您将修改客户的对象。所以你需要访问客户端的对象,这是移动语义不能给你的。
Func7
和Func8
是通常的情况。如果你只是访问,不需要自己存储副本,没有移动点语义;它可能会稍微慢一些而不是对const的引用。如果你要存储副本,那么移动语义可以产生显著的差异。