传递值和std :: move优于传递参考 [英] Advantages of pass-by-value and std::move over pass-by-reference

查看:461
本文介绍了传递值和std :: move优于传递参考的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在学习C ++,并尝试避免养成不良习惯。
据我了解,clang-tidy包含许多最佳实践,并且我会尽力坚持下去(即使我不一定理解为什么他们被认为是好的)

I'm learning C++ at the moment and try avoid picking up bad habits. From what I understand, clang-tidy contains many "best practices" and I try to stick to them as best as possible (even though I don't necessarily understand why they are considered good yet), but I'm not sure if I understand what's recommended here.

我使用了本教程中的此类:

I used this class from the tutorial:

class Creature
{
private:
    std::string m_name;

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

这导致clang-tidy建议我应该按值传递而不是引用并使用 std :: move
如果这样做,我会建议使用名称作为参考(以确保每次都不会复制它),并给出警告,指出 std :: move 不会有任何效果,因为 name const ,因此我应该删除它。

This leads to a suggestion from clang-tidy that I should pass by value instead of reference and use std::move. If I do, I get the suggestion to make name a reference (to ensure it does not get copied every time) and the warning that std::move won't have any effect because name is a const so I should remove it.

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

The only way I don't get a warning is by removing const altogether:

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

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

Which seems logical, as the only benefit of const was to prevent messing with the original string (which doesn't happen because I passed by value). But I read on CPlusPlus.com:


尽管要注意-在标准库中-移动意味着从源移出的对象处于有效但未指定的状态。这意味着在执行此操作后,仅应销毁移出对象的值或为其分配新值;

Although note that -in the standard library- moving implies that the moved-from object is left in a valid but unspecified state. Which means that, after such an operation, the value of the moved-from object should only be destroyed or assigned a new value; accessing it otherwise yields an unspecified value.

现在想象一下这段代码:

Now imagine this code:

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

因为 nameString 通过值传递, std :: move 只会使构造函数中的 name 无效,而不会触摸原始字符串。但是,这样做的好处是什么?内容似乎只能复制一次-如果在调用 m_name {name} 时通过引用传递,如果在传递时按值传递(然后传递)被感动)。我知道这比按值传递而不使用 std :: move 更好(因为它被复制了两次)。

Because nameString gets passed by value, std::move will only invalidate name inside the constructor and not touch the original string. But what are the advantages of this? It seems like the content gets copied only once anyhow - if I pass by reference when I call m_name{name}, if I pass by value when I pass it (and then it gets moved). I understand that this is better than passing by value and not using std::move (because it gets copied twice).

有两个问题:


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

  2. 是在通过引用传递时使用 std :: move 有什么好处,只是调用 m_name {name}

  1. Did I understand correctly what is happening here?
  2. Is there any upside of using std::move over passing by reference and just calling m_name{name}?


推荐答案



  1. 我正确理解了什么


是。



  1. 通过引用传递和仅调用 std :: move 有什么好处吗? m_name {name}

  1. Is there any upside of using std::move over passing by reference and just calling m_name{name}?


易于掌握功能签名,而没有任何其他重载。签名立即显示该参数将被复制-这使调用者不必怀疑 const std :: string& 引用是否可以存储为数据成员,从而有可能成为悬挂对象稍后参考。而且不需要在 std :: string&&名称 const std :: string& 参数可以避免在将右值传递给函数时不必要的复制。传递左值

An easy to grasp function signature without any additional overloads. The signature immediately reveals that the argument will be copied - this saves callers from wondering whether a const std::string& reference might be stored as a data member, possibly becoming a dangling reference later on. And there is no need to overload on std::string&& name and const std::string& arguments to avoid unnecessary copies when rvalues are passed to the function. Passing an lvalue

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

到按值接受参数的函数会导致一个副本和一个动作构造。将右值传递给同一函数

to the function that takes its argument by value causes one copy and one move construction. Passing an rvalue to the same function

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

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

causes two move constructions. In contrast, when the function parameter is const std::string&, there will always be a copy, even when passing an rvalue argument. This is clearly an advantage as long as the argument type is cheap to move-construct (this is the case for std::string).

但是有一个缺点要考虑:对于将函数参数分配给另一个变量(而不是初始化变量)的函数,这种推理不起作用:

But there is a downside to consider: the reasoning doesn't work for functions that assign the function argument to another variable (instead of initializing it):

void setName(std::string name)
{
    m_name = std::move(name);
}

会导致对 m_name 在重新分配之前引用。我建议阅读《有效的现代C ++》中的第41项,并此问题

will cause a deallocation of the resource that m_name refers to before it's reassigned. I recommend reading Item 41 in Effective Modern C++ and also this question.

这篇关于传递值和std :: move优于传递参考的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆