所以基本上我的问题是:什么时候我应该使用rvalue引用?在这个例子中,我正在研究一个记录器类(它只是将事情记录到控制台...)。我有不同的函数来记录不同日志级别的消息。它们以一个std::string作为参数。我是否应该为每个函数设置两个版本,第一个是 "普通 "引用,第二个是rvalue引用?
namespace lnr
{
class logger
{
public:
logger(const string& name);
logger(const string&& name);
~logger() = default;
const void trace(const string& message) const;
const void trace(const string&& message) const;
const void info(const string& message) const;
const void info(const string&& message) const;
const void warn(const string& message) const;
const void warn(const string&& message) const;
const void error(const string& message) const;
const void error(const string&& message) const;
private:
const string name;
};
}
因为用这两个函数来记录某些信息是很常见的。
logger.trace("Hello");
和
std::string error_message = "...";
logger.error(error_message);
但是每一个函数都要用两次真的很奇怪,而且似乎也有点不必要......
如果你要取一个字符串,你要复制和存储,你最好不要取引用。取一个值.
struct T
{
T(std::string str) : m_str(std::move(str)) {}
private:
std::string m_str;
};
现在,做这件事的人 T
(哈!)可以只传入一个现有的字符串,在不影响原始字符串的情况下进行复制......或者他们可以 std::move
一串他们不需要的东西了。
所以,如果你需要副本,你只需获得一份;如果你不需要,你只需获得一串动作。又好又便宜!
如果你吸收一个字符串只是为了在该函数中使用,也就是说,你不是为了在该函数中使用 当家作主没必要为这些事烦心了 只要接受一个漂亮的老式的 const std::string&
.
void foo(const std::string& str)
{
std::cout << str << '\n';
}
虽然有一些罕见的例外,但我通常 只是 当函数是一个移动构造函数或移动赋值操作符时,让函数接受一个 rvalue 引用。我们这样做是因为语言的 "重载解析 "规则的语义是围绕着移动的工作方式建立起来的(而且因为像我第一个例子中那样,当我们没有 "目标 "对象可以放入时,有一个可能的副本是不可取的)。
你也会看到像 auto&&
或 T&&
哪儿 T
是一个模板参数。这实际上不是一个r值引用,而是一个所谓的 转发参考当你想根据模板上下文尽可能地传递一个参数的rvalue-ness时,它就会被使用。