在C ++中,i ++和++ i之间有性能差异吗?

我们有问题, 在C中i++++i之间有性能差异吗?

C ++的答案是什么?


[内容提要:使用++i ,如果你没有特别原因需要使用i++ ]

对于C ++来说,答案有点复杂。

如果i是一个简单类型(不是C ++类的一个实例),那么由于编译器正在生成代码,因此C(“不存在性能差异”)给出的答案成立。

但是,如果i是一个C ++类的实例,那么i++++i正在调用其中一个operator++函数。 以下是这些功能的标准配对:

Foo& Foo::operator++()   // called for ++i
{
    this->data += 1;
    return *this;
}

Foo Foo::operator++(int ignored_dummy_value)   // called for i++
{
    Foo tmp(*this);   // variable "tmp" cannot be optimized away by the compiler
    ++(*this);
    return tmp;
}

由于编译器不生成代码,而只是调用operator++函数,因此无法优化tmp变量及其关联的拷贝构造函数。 如果拷贝构造函数很昂贵,那么这会对性能产生重大影响。


是。 有。

++运算符可能被定义或不定义为一个函数。 对于原始类型(int,double,...),运算符是内置的,因此编译器可能会优化您的代码。 但是在定义++运算符的对象的情况下,情况是不同的。

运算符++(int)函数必须创建一个副本。 这是因为postfix ++需要返回一个不同于它所保存的值:它必须在temp变量中保存它的值,增加它的值并返回temp。 在operator ++(),前缀++的情况下,不需要创建副本:对象可以自行增加,然后简单地返回它自己。

这里是一个例子:

struct C
{
    C& operator++();      // prefix
    C  operator++(int);   // postfix

private:

    int i_;
};

C& C::operator++()
{
    ++i_;
    return *this;   // self, no copy created
}

C C::operator++(int ignored_dummy_value)
{
    C t(*this);
    ++(*this);
    return t;   // return a copy
}

每次调用operator ++(int)时,都必须创建一个副本,编译器无法对此做任何事情。 当给出选择时,使用operator ++(); 这样你就不会保存副本。 在许多增量(大循环?)和/或大对象的情况下,它可能很重要。


以下是递增运算符处于不同翻译单位时的基准。 用g ++ 4.5编译。

现在忽略样式问题

// a.cc
#include <ctime>
#include <array>
class Something {
public:
    Something& operator++();
    Something operator++(int);
private:
    std::array<int,PACKET_SIZE> data;
};

int main () {
    Something s;

    for (int i=0; i<1024*1024*30; ++i) ++s; // warm up
    std::clock_t a = clock();
    for (int i=0; i<1024*1024*30; ++i) ++s;
    a = clock() - a;

    for (int i=0; i<1024*1024*30; ++i) s++; // warm up
    std::clock_t b = clock();
    for (int i=0; i<1024*1024*30; ++i) s++;
    b = clock() - b;

    std::cout << "a=" << (a/double(CLOCKS_PER_SEC))
              << ", b=" << (b/double(CLOCKS_PER_SEC)) << 'n';
    return 0;
}

O(n)增量

测试

// b.cc
#include <array>
class Something {
public:
    Something& operator++();
    Something operator++(int);
private:
    std::array<int,PACKET_SIZE> data;
};


Something& Something::operator++()
{
    for (auto it=data.begin(), end=data.end(); it!=end; ++it)
        ++*it;
    return *this;
}

Something Something::operator++(int)
{
    Something ret = *this;
    ++*this;
    return ret;
}

结果

在虚拟机上使用g ++ 4.5的结果(时间以秒为单位):

Flags (--std=c++0x)       ++i   i++
-DPACKET_SIZE=50 -O1      1.70  2.39
-DPACKET_SIZE=50 -O3      0.59  1.00
-DPACKET_SIZE=500 -O1    10.51 13.28
-DPACKET_SIZE=500 -O3     4.28  6.82

O(1)增量

测试

现在让我们看看以下文件:

// c.cc
#include <array>
class Something {
public:
    Something& operator++();
    Something operator++(int);
private:
    std::array<int,PACKET_SIZE> data;
};


Something& Something::operator++()
{
    return *this;
}

Something Something::operator++(int)
{
    Something ret = *this;
    ++*this;
    return ret;
}

它在增量中没有做任何事情。 这模拟了增量具有不变复杂性的情况。

结果

结果现在变化极大:

Flags (--std=c++0x)       ++i   i++
-DPACKET_SIZE=50 -O1      0.05   0.74
-DPACKET_SIZE=50 -O3      0.08   0.97
-DPACKET_SIZE=500 -O1     0.05   2.79
-DPACKET_SIZE=500 -O3     0.08   2.18
-DPACKET_SIZE=5000 -O3    0.07  21.90

结论

性能方面

如果你不需要以前的值,那就习惯使用预增值。 即使与内置类型保持一致,您也会习惯它,并且如果您使用自定义类型替换内置类型,则不会冒着遭受不必要性能损失的风险。

语义明智

  • i++increment i, I am interested in the previous value, though
  • ++iincrement i, I am interested in the current valueincrement i, no interest in the previous value 。 再一次,即使你现在不适应,你也会习惯它。
  • 克努特。

    不成熟的优化是万恶之源。 由于过早的悲观化。

    链接地址: http://www.djcxy.com/p/72251.html

    上一篇: Is there a performance difference between i++ and ++i in C++?

    下一篇: c++