首页 > 解决方案 > 何时使用右值引用

问题描述

所以基本上我的问题是:我什么时候应该使用右值引用?在这个例子中,我正在研究一个记录器类(它只是将事情记录到控制台......)。我有不同的功能来记录不同日志级别的消息。他们接受一个 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;
    };
}

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

logger.trace("Hello");

std::string error_message = "...";
logger.error(error_message);

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

标签: c++parametersrvalue-referencervalue

解决方案


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

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';
}

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

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


推荐阅读