9

如果我们去维基百科关于 C++ 运算符的文章,我们有一个例子:

Addition : a + b -> T T::operator +(const T& b) const;

所以运算符返回一个类型为 T 的非常量。如果我们看一下这个指南,作者说返回类型应该是一个const以避免以下语法:

(a+b) = c

现在假设这种语法不会打扰我,并认为 a 和 b 是大数组。从“纯”性能的角度来看,返回类型中缺少 const 关键字是否会阻止编译器的优化(g++ 和带有 -O3 的 intel icpc)?如果回答是“是”,为什么?

4

3 回答 3

7

这是个有趣的问题。在 C++03 中,使用这两个选项中的任何一个进行优化都没有更好的机会,这将是一个风格选择的问题(我自己不相信整个回报是const为了避免不太可能出现的错误)。

另一方面,在 C++11 中,它实际上可能会产生影响。特别是,如果您的类型支持移动操作,并且无法省略返回值的复制/移动,那么通过const您返回实际上是禁用移动*

// T is move assignable, with the usual declaration of a move assignment operator
T f();
const T g();
int main() {
   T t;
   t = f();     // can move
   t = g();     // cannot move!!!
}

在您的特定情况下,这取决于大型数组对您意味着什么,如果它们是std::array(或者具有自动存储的数组),那么它们不能被移动,所以这无论如何都不是一个选项,但是如果大型数组是动态分配的记忆,移动将比复制更有效率。请注意,在 C++11 中,存在而不是不存在const会导致性能损失。


*这不是100% 正确的,如果移动赋值运算符通过rvalue-reference获取参数const,那么它可以被移动。但是标准库中的任何类型都没有以这种方式接受参数,我也不希望人们这样做(它需要const_cast移动操作(构造函数/赋值)中,这没有任何意义:如果你计划从中移动(窃取),您为什么声称不修改它?

于 2012-08-12T03:07:34.587 回答
2

由于您要返回 type 的临时右值实例T,因此该语句不会做任何事情,除非在赋值操作中有一些全局副作用,例如修改作为 type 数据成员的静态变量T,输出到终端等。因此,根据类型,以及赋值运算符是否是编译器默认赋值运算符,整个操作可以在优化过程中安全地省略。如果 type 有用户定义的赋值运算符T,则不会省略赋值操作,但如前所述,除非存在全局副作用,否则在语句执行的生命周期之后不会做任何事情因为您没有存储c在驻留在命名且可访问的内存位置的对象中。

请记住,如果您确实将返回T类型声明为const,并且您的运算符方法不是const类方法,您将禁用某些类型的运算符链接,以及许多其他有用的东西,例如调用具有 side-效果。例如:

(a+b).print(); //assuming print() is non-const method

或假设 operator+不是const类方法,

d = (a+b) + c;
于 2012-08-12T02:26:30.973 回答
0

我会说永远不要实现operator +为成员函数。只需实现operator +=绝对不是 const 即可。然后你提供一个关注 的全局函数operator +,我认为这是最常见的方法。

T& T::operator +=(const T& t)
{
    // add t to object ...
    return *this;
}

T operator +(T t1, const T& t2)
{
    t1 += t2
    return t1; // RVO will eliminate copy (or move constructor)
}
于 2012-08-12T07:52:11.503 回答