何时使用右值引用

man*_*l34 2 c++ parameters rvalue rvalue-reference

所以基本上我的问题是:我什么时候应该使用右值引用?在这个例子中,我正在处理一个记录器类(它只是将事情记录到控制台......)。我有不同的功能来记录不同日志级别的消息。他们接受一个 std::string 作为参数。我应该有每个函数的两个版本,第一个用于“正常”引用,第二个用于右值引用?

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;
    };
}
Run Code Online (Sandbox Code Playgroud)

因为用两者记录一些东西是很常见的

logger.trace("Hello");
Run Code Online (Sandbox Code Playgroud)

std::string error_message = "...";
logger.error(error_message);
Run Code Online (Sandbox Code Playgroud)

但是每个函数都重复两次真的很奇怪,而且似乎也有点不必要......

Ast*_*ngs 5

如果您要接收要复制和存储的字符串,最好根本不要引用:获取值

struct T
{
    T(std::string str) : m_str(std::move(str)) {}

private:
    std::string m_str;
};
Run Code Online (Sandbox Code Playgroud)

现在,制作T(hah!) 的人可以只传入一个现有的字符串,该字符串将被复制而不会影响原始字符串……或者他们可以输入std::move一个不再需要的字符串。

所以,如果你需要一份副本,你只需要一份;如果你不这样做,你只会得到一连串的动作。又好又便宜!


如果您接收一个字符串只是为了在该函数中使用,即您没有获得所有权,则没有理由为此烦恼。只接受一个漂亮的老式const std::string&

void foo(const std::string& str)
{
   std::cout << str << '\n';
}
Run Code Online (Sandbox Code Playgroud)

尽管有一些罕见的例外,但我通常只有一个函数在它是移动构造函数或移动赋值运算符时才采用右值引用。我们这样做是因为语言的“重载解决”规则的语义是围绕以这种方式工作的移动而构建的(并且因为当我们没有“目标”对象时,不希望有一个可能的副本,就像我的第一个例子一样)。

您还将看到诸如auto&&, 或模板参数T&&where 之类的T内容。这实际上不是一个右值引用,而是一个所谓的转发引用,当您想尽可能传递参数的右值时,它会使用,具体取决于模板上下文。