小编典典

值传递和 std::move 优于传递引用的优点

all

我目前正在学习 C++,并尽量避免养成坏习惯。据我了解,clang-tidy 包含许多“最佳实践”,我尽量坚持使用它们(尽管我不一定明白 为什么
它们被认为是好的),但我不确定我是否了解这里推荐的内容。

我使用了教程中的这个类:

class Creature
{
private:
    std::string m_name;

public:
    Creature(const std::string &name)
            :  m_name{name}
    {
    }
};

这导致了 clang-tidy 的建议,即我应该通过 value 而不是 reference 和 use
传递std::move。如果我这样做了,我会收到建议进行name引用(以确保它不会每次都被复制)以及std::move不会产生任何影响的警告,因为name是一个const所以我应该删除它。

我没有收到警告的唯一方法是const完全删除:

Creature(std::string name)
        :  m_name{std::move(name)}
{
}

这似乎是合乎逻辑的,因为唯一的好处const是防止弄乱原始字符串(这不会发生,因为我按值传递)。但我在CPlusPlus.com上读到:

尽管请注意 - 在标准库中 -
移动意味着被移动的对象处于有效但未指定的状态。这意味着,在这样的操作之后,被移动对象的值应该只被销毁或分配一个新值;否则访问它会产生一个未指定的值。

现在想象一下这段代码:

std::string nameString("Alex");
Creature c(nameString);

因为nameString按值传递,std::move只会name在构造函数内部无效,不会触及原始字符串。但是这样做有什么好处呢?无论如何,内容似乎只被复制一次

如果我在调用时通过引用传递m_name{name},如果我在传递它时通过值传递(然后它被移动)。我知道这比按值传递而不是使用要好std::move(因为它被复制了两次)。

所以两个问题:

  1. 我是否正确理解了这里发生的事情?
  2. std::move使用通过引用传递并只是调用有什么好处m_name{name}吗?

阅读 59

收藏
2022-08-19

共1个答案

小编典典

  1. 我是否正确理解了这里发生的事情?

是的。

  1. std::move使用通过引用传递并只是调用有什么好处m_name{name}吗?

一个易于掌握的函数签名,没有任何额外的重载。签名立即显示该参数将被复制 - 这使调用者不必怀疑const std::string&引用是否可能存储为数据成员,以后可能会成为悬空引用。当右值传递给函数时,不需要重载std::string&& name和参数以避免不必要的副本。const std::string&传递左值

std::string nameString("Alex");
Creature c(nameString);

通过值获取参数的函数会导致一个副本和一个移动构造。将右值传递给同一个函数

std::string nameString("Alex");
Creature c(std::move(nameString));

导致两个移动结构。相反,当函数参数为const std::string&时,即使传递右值参数,也总会有一个副本。这显然是一个优势,只要参数类型对移动构造便宜(这是 的情况std::string)。

但是有一个缺点需要考虑:推理不适用于将函数参数分配给另一个变量(而不是初始化它)的函数:

void setName(std::string name)
{
    m_name = std::move(name);
}
2022-08-19