康斯坦德是做什么的?

What does const& do?

本文关键字:什么 斯坦德 康斯坦      更新时间:2023-10-16

我不明白这是怎么回事。我刚刚学习c++,我经常看到这样的东西:

double some_function(const Struct_Name& s) {
    ...
}

如果我们通过引用传递,为什么是const ?

当您不想(或不能)修改传入的参数,并且您不希望复制对象可能会导致性能下降时,您可以通过const引用传递。

const引用防止对象被修改,就像const在其他地方一样,但也避免了复制的潜在成本。

你在告诉编译器你永远不会改变s。

这使它能够进行一些优化,否则它将无法做到。基本上,它提供了与按值传递相同的语义,但不会导致调用复制构造函数的性能损失。

通过const-reference调用避免了Struct_Name的复制,同时保证不修改它。

这既有性能上的原因,也有语义上的原因。

如果Struct_Name很大,复制它在时间和内存上都很昂贵。

如果Struct_Name是不可复制的(或在复制时无效),则不可能按值调用或引入不必要的复杂性。例如:std::unique_ptrstd::auto_ptr

通过使用const,我们可以通知函数的用户和编译器,作为参数s传递的对象在函数内部不会被更改(这实际上是可能的,因为我们通过引用传递它!)如果我们不小心修改了对象,编译器可能会给我们一个错误,它可以做一些其他情况下无法做的优化。

一个额外的优点是,如果函数的调用者只拥有指向对象的const指针,它仍然可以将该对象作为参数提供,而不需要强制转换。

const这里承诺some_function不会修改参数,

double some_function(const Struct_Name& s) {
    ...
}

你可以尝试修改它,但是编译器会返回错误。实际上,constness要求你仔细编写Struct_Name内部方法。你将不能在some_function内部调用对象上的非const函数。你可以试试,但你会得到错误。即:

struct Struct_Name {
  void myfun() const { } // can be called from some_function
  void myfun2() { } // will show error if called from some_function
};
从设计的角度来看,使用const参数是好的,如果你知道某些函数不应该改变你的对象,那么你就添加const。这意味着没有其他程序员可以对一些隐藏在类层次结构中的代码进行修改,这些代码将修改您的对象。

另一个没有人提到的原因——如果输入值不是参数中声明的确切类型,但该类型有一个支持传入类型的构造函数,则通过const引用允许编译器创建并传递临时对象,而不会产生警告。

例如:

void foo(const std::string &s)
{
    ...
}
foo("hello"); // OK

foo()期望std::string,但收到的却是const char*。由于std::string有一个接受const char*的构造函数,编译器生成的代码可以有效地执行以下操作:

std::string temp("hello");
foo(temp);

编译器知道参数是const, foo()不会改变临时,foo()退出后临时将被丢弃,所以它不会抱怨必须创建一个临时。

如果参数通过值传递(const或非const,这无关紧要),而不是通过引用传递,也会发生同样的事情:

void foo(const std::string s)
{
    ...
}
void bar(std::string s)
{
    ...
}
foo("hello"); // OK
bar("world"); // OK

这实际上与以下相同:

{
std::string temp1("hello");
foo(temp1);
}
{
std::string temp2("world");
bar(temp2);
}

同样,编译器不会报错,因为它知道临时变量不会影响调用代码,并且bar()中对临时变量所做的任何更改都将被安全地丢弃。

如果参数是一个非const引用,传递const char*将生成一个关于必须创建的临时的警告,以满足引用绑定。这个警告是为了让您知道,函数对临时对象(因为它不是const)所做的任何更改都会在函数退出时丢失,这可能会对调用代码产生影响,也可能不会。这通常表示在这种情况下不应该使用临时变量:

void foo(std::string &s)
{
    ...
}
foo("hello"); // warning!