为什么要将对象的副本作为函数的参数?为什么const ref不是参数的默认方式?

Why would you ever take the copy of an object as a parameter to your function? Why are not const ref the default way of parameters?

尽管我很喜欢 C++ 编程,但有一件事我真的不明白。对我来说,似乎最常见的函数编程方式是这样的:

some_function(a variable)
    do something according to the data in the variable

示例:

bool match_name(const std::string& name)
{
    return this->name == name;
}

我发现自己在我的代码中对所有函数参数的 90% 使用了 const ref(也许我做错了什么)。

我的问题是:为什么变量的副本是"default"类型的参数?为什么 const ref 不是默认值?

为什么不是类似的东西?:

void my_function(My_type object)      // <- const ref

void my_function(ref My_type object)  // <- ref (mutable)

void my_function(copy My_type object) // <- copy

除了历史原因,这将产生非常丑陋的影响。它基本上意味着 MyType myVarName 在函数范围或在函数参数列表中使用时会有不同的含义。

void foo(MyType myVar) //myVar is const ref
{
    MyType anotherVar = myVar; // anotherVar is a copy, what?
    const MyType& myVarRef = myVar; //a reference, but it looks like it has different type than myVar?
}

想想穷人&!除非你提出一种不同的方式来区分 refs 和 non-refs,否则你最终会得到

void foo(MyType& myVar) //myVar is a copy?
{
    MyType& anotherVar = myVar; // anotherVar is a reference???
}

C++ 具有完善的对象和对象引用概念。后者总是通过在类型中添加 & 来表示。你的提议会把事情搞砸,C++ 会比现在更难理解。

C++ 想要与 C 兼容,并且由于 C 默认使用值语义,因此 C++ 也是如此。按值获取内置类型而按引用获取其他类型是非常不一致的。

但是,通过引用传递并不总是更好。引用导致的指针间接寻址通常会使编译器更难优化代码生成。在许多情况下,按值传递类型仍然比按引用传递更好。这取决于类型。引用的指针间接可能会导致内存读取,而按值传递允许对象在 CPU 寄存器中传递。例如,这样的类型:

class Point {
public:
    /* functions */
private:
    int x;
    int y;
};

应始终按值传递。它只是两个整数。引用可能会导致不必要的内存读取以获取值。

此外,有时即使无法注册类型,您也希望按值传递。由于移动语义,所谓的 "sink functions" 需要存储传递的值,因此对值执行得更好。主要示例是构造器和设置器:

void SomeClass::setString(std::string s)
{
    this->s_ = std::move(s);
}

在这种情况下通过引用传递会产生额外的副本。您可以在线阅读更多内容。一个很好的起点是这个 SO 问题:

Are the days of passing const std::string & as a parameter over?