假设我有一个ThisHasAStringMember
类。假设它有一个私有成员,它是一个字符串,并且我想有效地获取字符串值,在可能的情况下,希望将其移到副本上。以下两个构造函数可以做到吗?
class ThisHasAStringMember
{
public:
// ctors
ThisHasAStringMember(const std::string str) : m_str(str) {}
ThisHasAStringMember(std::string &&str) : m_str(std::move(str)) {}
// getter (no setter)
std::string value() { return m_str; }
private:
std::string m_str;
}
第二个构造函数中的str
参数前是否需要双与号?
这是实现此目标的正确方法吗?
答案 0 :(得分:2)
起初,我会注意到最好将构造函数标记为显式。
下一步是更好地将解决方案中的第一个构造函数更改为采用const引用,以避免复制左值:
// ctors
ThisHasAStringMember(const std::string& str) : m_str(str) {}
ThisHasAStringMember(std::string &&str) : m_str(std::move(str)) {}
从性能角度来看,这种方法是最佳的(您将有一个复制构造函数调用左值,一个移动构造函数调用右值),但是在这种情况下,每次实现两个构造函数都非常无聊。如果您有N个成员-2 ^ N个构造函数。
几乎没有其他选择:
信号构造函数,您可以在其中仅按值传递参数。是的,它在C ++ 98中效率不高,但是在C ++ 11中,当您创建完整副本时-这是一个选择。
ThisHasAStringMember(std::string str) : m_str(std::move(str)) {}
传递左值时,将有一个复制构造函数调用和一个移动构造函数调用。当传递右值时,将有两个move构造函数调用。是的,在每种情况下,您都有一个额外的move构造函数调用。但这通常很便宜(甚至可以通过编译器进行优化),并且代码非常简单。
通过rvalue传递参数的单个构造函数:
ThisHasAStringMember(std::string&& str) : m_str(std::move(str)) {}
如果传递左值,则必须首先在调用位置显式复制它,例如
ThisHasAStringMember(copy(someStringVar))。 (这里copy
是一种简单的模板复制方法)。而且,对于左值,您仍然会有一个额外的move构造函数调用。对于右值,将没有任何开销。我个人喜欢这种方法:复制参数的所有位置都是明确的,您不会在性能至关重要的位置偶尔创建副本。
template <typename String,
std::enable_if_t<std::is_constructible_v<std::string, String>>* = nullptr>
ThisHasAStringMember(String&& str) : m_str(std::forward<String>(str))
{}
rvalues和lvalues都没有开销,但是在大多数情况下,您需要制作构造函数模板并在标头中定义它。