10
void do_something() {....}

struct dummy
{
   //even I dont call this, compiler will call it fall me, they need it
   void call_do_something() { this->do_something_member(); } 
   void do_something() {....}
};

据我所知,C++ 中的每个类或结构都会在您要访问该类的数据成员或成员函数时隐式调用此指针,这会给 C++ 带来性能损失吗?

我的意思是

int main()
{
  do_something(); //don't need this pointer
  dummy().call_do_something(); //assume the inline is prefect

  return 0;
}

call_do_something 需要一个 this 指针来调用成员函数,但是像 do_something 这样的 C 不需要 this 指针,与 C 类函数相比,这个指针会带来一些性能损失吗?

我没有做任何微优化的意思,因为它会占用我很多时间但总是不能给我带来好的结果,我总是遵循“衡量,不要思考”的规则。我想知道这个指针是否会因为好奇而带来性能损失。

4

2 回答 2

8

视情况而定,但通常,如果您启用了优化,它不应该比 C 版本贵。唯一真正为this其他功能“付费”的时候是在使用继承和虚函数时。除此之外,编译器足够聪明,不会this在你不使用它的函数上浪费时间。考虑以下:

#include <iostream>

void globalDoStuff()
{
    std::cout << "Hello world!\n";
}

struct Dummy
{
    void doStuff() { callGlobalDoStuff(); }
    void callGlobalDoStuff() { globalDoStuff(); }
};

int main()
{
    globalDoStuff();

    Dummy d;
    d.doStuff();
}

使用 GCC 优化级别编译O3,我得到以下反汇编(删除多余的垃圾并仅显示main()):

_main:
0000000100000dd0    pushq   %rbp
0000000100000dd1    movq    %rsp,%rbp
0000000100000dd4    pushq   %r14
0000000100000dd6    pushq   %rbx
0000000100000dd7    movq    0x0000025a(%rip),%rbx
0000000100000dde    leaq    0x000000d1(%rip),%r14
0000000100000de5    movq    %rbx,%rdi
0000000100000de8    movq    %r14,%rsi
0000000100000deb    callq   0x100000e62 # bypasses globalDoStuff() and just prints "Hello world!\n"
0000000100000df0    movq    %rbx,%rdi
0000000100000df3    movq    %r14,%rsi
0000000100000df6    callq   0x100000e62 # bypasses globalDoStuff() and just prints "Hello world!\n"
0000000100000dfb    xorl    %eax,%eax
0000000100000dfd    popq    %rbx
0000000100000dfe    popq    %r14
0000000100000e00    popq    %rbp
0000000100000e01    ret

请注意,它完全优化了DummyglobalDoStuff(),只是将其替换为globalDoStuff(). globalDoStuff()甚至没有被调用过,也没有Dummy被构造过。相反,编译器/优化器用两个系统调用替换该代码以"Hello world!\n"直接打印出来。教训是编译器和优化器非常聪明,通常你不会为你不需要的东西买单。

另一方面,假设您有一个操作成员变量的成员函数Dummy。您可能会认为这与 C 函数相比会受到惩罚,对吧?可能不是,因为 C 函数需要一个指向要修改的对象的指针,当您考虑它时,这正是this指针的开头。

因此,一般而言,与 C 相比,在 C++ 中您不会为 C++ 支付额外费用this。虚函数可能会受到(小)惩罚,因为它必须查找要调用的正确函数,但这不是我们在这里考虑的情况。

如果您不在编译器中打开优化,那么是的,当然,可能会涉及到惩罚,但是......为什么要比较未优化的代码?

于 2012-11-30T06:17:15.390 回答
3
#include <iostream>
#include <stdint.h>
#include <limits.h>
struct Dummy {
  uint32_t counter;
  Dummy(): counter(0) {}
  void do_something() {
    counter++;
  }
};

uint32_t counter = 0;

void do_something() { counter++; }

int main(int argc, char **argv) {
  Dummy dummy;
  if (argc == 1) {
    for (int i = 0; i < INT_MAX - 1; i++) {
      for (int j = 0; j < 1; j++) {
        do_something();
      }   
    }   
  } else {
    for (int i = 0; i < INT_MAX - 1; i++) {
      for (int j = 0; j < 1; j++) {
        dummy.do_something();
      }   
    }   
    counter = dummy.counter;
  }
  std::cout << counter << std::endl;
  return 0;
}

在 64 位 gcc 版本 4.3.5 (Debian 4.3.5-4) 上平均运行 10 次,没有任何标志:

带全局计数器:0m15.062s

带虚拟对象:0m21.259s

如果我按照Lyth的建议修改这样的代码:

#include <iostream>
#include <stdint.h>
#include <limits.h>

uint32_t counter = 0;

struct Dummy {
  void do_something() {
    counter++;
  }
};


void do_something() { counter++; }

int main(int argc, char **argv) {
  Dummy dummy;
  if (argc == 1) {
    for (int i = 0; i < INT_MAX; i++) {
        do_something();
    }   
  } else {
    for (int i = 0; i < INT_MAX; i++) {
        dummy.do_something();
    }   
  }
  std::cout << counter << std::endl;
  return 0;
}

然后,奇怪的是,

带全局计数器:0m12.062s

带虚拟对象:0m11.860s

于 2012-11-30T06:37:27.097 回答