const参数与const参考参数

时间:2012-12-17 16:45:24

标签: c++ optimization reference const alias

实施1:

foo(const Bar x);

实施2:

foo(const Bar & x);

如果在函数中不更改对象,为什么要复制它(实现1)。

编译器会自动优化吗?

摘要:即使对象在函数声明中声明为const,仍然可以通过其他别名&编辑对象。

如果您是编写库的人并且知道您的功能没有这样做,或者该对象足够大以证明每次操作的解除引用成本,那么 foo(const Bar & x);是要走的路。

第2部分

  

编译器会自动优化吗?

由于我们确定它们并不总是等价的,并且等价的条件非常重要,编译器通常很难确保它们,所以几乎可以肯定 no

4 个答案:

答案 0 :(得分:5)

实际上,在这种情况下,您通常会使用方法2.

通常情况下,如果对象很小,您只会使用方法1,因此复制它一次比通过引用重复访问它更便宜(这也会产生成本)。在TC++PL中,Stroustrup开发了一个复数类,并按正确的值传递它。

答案 1 :(得分:4)

你问,

  

“如果在函数中不更改对象,为什么要复制它(实现1)。”

有一些奇怪的情况,通过引用传递的对象可能会被其他代码更改,例如

namespace g { int x = 666; }

void bar( int ) { g::x = 0; }

int foo( int const& a ) { assert( a != 0 );  bar( a );  return 1000/a; }  // Oops

int main() { foo( g::x ); }
自从20世纪90年代中期以来,这种情况从未发生过。

因此,别名是该类型的单个参数的理论问题

有两个相同类型的参数,它更有可能。例如,赋值运算符可能会传递它被调用的对象。当参数按值传递时(如交换习语的最小形式),这没有问题,但如果没有,则通常需要避免自我赋值

你进一步问,

  

“这会由编译器自动优化吗?”

不,一般情况下,由于上述原因

编译器通常不能保证参数参数不会有别名(但是,一个例外是调用内联机器代码的地方)

然而,第三方面,语言可能可能已经支持编译器,例如,通过为程序员提供一种明确接受任何此类优化的方法,比如说“通过引用传递替换pass by value来优化此代码是安全的,请继续,编译器”

答案 2 :(得分:2)

在某些情况下可能会进行优化,但有很多事情可以阻止它。如果出现以下情况,编译器无法避免复制:

  • 复制构造函数或析构函数有副作用,传递的参数不是临时的。
  • 您获取x的地址或对其的引用,并将其传递给某些可能与原始地址进行比较的代码。
  • foo运行时对象可能会发生变化,例如,因为foo会调用某些其他函数来更改它。我不确定这是否是你的意思是通过说“该对象不会在函数中被”来排除,但如果没有那么它就在游戏中。

如果这些事情对您的计划有任何影响,您可以复制它:

  • 如果您想要复制的副作用,请复制
  • 如果您希望“您的”对象与用户提供的参数具有不同的地址,请复制
  • 如果您不希望在运行功能期间看到对原始文件所做的更改,请复制

如果您认为副本效率更高,您也会复制它,这通常被认为是int等“小”类型的情况。标准算法中的迭代器和谓词也是按值进行的。

最后,如果您的代码计划无论如何都要复制对象(包括通过分配给现有对象),那么合理的习惯用法就是首先将副本作为参数。然后从参数中移动/交换。

答案 3 :(得分:1)

如果对象从其他地方更改怎么办?

void f(const SomeType& s);
void g(const SomeType s);

int main() {
    SomeType s;

    std::thread([&](){ /* s is non-const here, and we can modify it */}

    // we get a const reference to the object which we see as const, 
    // but others might not. So they can modify it.
    f(s);

    // we get a const *copy* of the object, 
    // so what anyone else might do to the original doesn't matter 
    g(s);
}

如果对象是const,但有可变成员怎么办?然后你仍然可以修改对象,因此,无论你有原件的副本还是引用都非常重要。

如果对象包含指向另一个对象的指针怎么办?如果s是const,则指针将是const,但指向的内容不受s的常量影响。但是创建一个副本会(希望)给我们一个深层副本,所以我们得到了我们自己的(const)对象,其中一个单独的(const)指针指向一个单独的(非const)对象。

在许多情况下,const副本与const引用不同。