优化C ++类与C结构一样快

时间:2015-09-22 12:48:07

标签: c++ class struct

使用以下类定义可以改变什么来创建和销毁这些对象,并尽可能快地将它们作为函数参数传递?有一个类的原因是需要运算符重载。

班级定义:

class MyType {
    int _a, _b, _c;
    MyType(int a, int b, int c) : _a(a), _b(b), _c(c) {}
    MyType(MyType & mt) : a(mt.a), b(mt.b), c(mt.c) {}
    ~MyType() {}
    MyType operator+(MyType & op) {/* do something */}
}

结构定义:

struct MyTypeC {
    int a; int b; int c;
};

一个程序应该在几乎相同的CPU时间运行,无论是否使用这两种类型:

void f(MyType & mt) {mt; return;}
void g(MyTypeC & mtc) {mtc; return;}

void TestCpp() {
    for (int i=1e5; --i; ) {
        MyType mt(0, 1, 2);
        f(mt);
    }
}

void TestC() {
    for (int i=1e5; --i; ) {
        MyTypeC mtc = {.a=0, .b=1, .c=2};
        g(mtc);
    }
}

即,在MyType中可以改变什么来使运行函数TestCpp()的CPU时间几乎与运行函数TestC()一样快?

编辑:

添加了MyType的成员函数的完整列表。

这些是每个相应功能的一些运行时CPU时序:

time (TestC)   = 0.000618 s
time (TestCpp) = 0.001373 s

2 个答案:

答案 0 :(得分:1)

你的问题的答案是双重的:

  1. 您的源代码甚至没有编译,因此我假设您从未运行过代码。因此,您的问题不是基于任何观察。两者都同样快。此外,如果您运行了代码的优化版本,您会看到优化器生成的机器代码几乎相当于两种情况下的NOP。即它们具有相同的速度。
  2. structclass在C ++中几乎相同。默认访问对于类是私有的(这是您的代码无法编译的原因之一 - 私有构造函数);对结构公开。您可以使用与类相同的方式派生和模板以及结构。只要类代码和结构代码都相同,就没有区别。
  3. 只是为了你的娱乐:如果你不愿意真正使用你的代码,那么最终的汇编程序看起来就是这样,一旦注意到,你首先就不会问这个问题:

    ; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.23026.0 
    
        TITLE   E:\R\playground\temp\ConsoleApplication2\ConsoleApplication2.cpp
        .686P
        .XMM
        include listing.inc
        .model  flat
    
    INCLUDELIB OLDNAMES
    
    EXTRN   @__security_check_cookie@4:PROC
    PUBLIC  _main
    PUBLIC  ?TestC@@YAXXZ                   ; TestC
    PUBLIC  ?TestCpp@@YAXXZ                 ; TestCpp
    PUBLIC  ?g@@YAXAAUMyTypeC@@@Z               ; g
    PUBLIC  ?f@@YAXAAVMyType@@@Z                ; f
    PUBLIC  ??0MyType@@QAE@HHH@Z                ; MyType::MyType
    ; Function compile flags: /Ogtp
    ;   COMDAT ??0MyType@@QAE@HHH@Z
    _TEXT   SEGMENT
    _a$dead$ = 8                        ; size = 4
    _b$dead$ = 12                       ; size = 4
    _c$dead$ = 16                       ; size = 4
    ??0MyType@@QAE@HHH@Z PROC               ; MyType::MyType, COMDAT
    ; _this$ = ecx
    ; File e:\r\playground\temp\consoleapplication2\consoleapplication2.cpp
    ; Line 9
        mov DWORD PTR [ecx], 0
        mov eax, ecx
        mov DWORD PTR [ecx+4], 1
        mov DWORD PTR [ecx+8], 2
        ret 12                  ; 0000000cH
    ??0MyType@@QAE@HHH@Z ENDP               ; MyType::MyType
    _TEXT   ENDS
    ; Function compile flags: /Ogtp
    ;   COMDAT ?f@@YAXAAVMyType@@@Z
    _TEXT   SEGMENT
    ?f@@YAXAAVMyType@@@Z PROC               ; f, COMDAT
    ; _mt$dead$ = ecx
    ; File e:\r\playground\temp\consoleapplication2\consoleapplication2.cpp
    ; Line 17
        ret 0
    ?f@@YAXAAVMyType@@@Z ENDP               ; f
    _TEXT   ENDS
    ; Function compile flags: /Ogtp
    ;   COMDAT ?g@@YAXAAUMyTypeC@@@Z
    _TEXT   SEGMENT
    ?g@@YAXAAUMyTypeC@@@Z PROC              ; g, COMDAT
    ; _mtc$dead$ = ecx
    ; File e:\r\playground\temp\consoleapplication2\consoleapplication2.cpp
    ; Line 18
        ret 0
    ?g@@YAXAAUMyTypeC@@@Z ENDP              ; g
    _TEXT   ENDS
    ; Function compile flags: /Ogtp
    ;   COMDAT ?TestCpp@@YAXXZ
    _TEXT   SEGMENT
    ?TestCpp@@YAXXZ PROC                    ; TestCpp, COMDAT
    ; File e:\r\playground\temp\consoleapplication2\consoleapplication2.cpp
    ; Line 25
        ret 0
    ?TestCpp@@YAXXZ ENDP                    ; TestCpp
    _TEXT   ENDS
    ; Function compile flags: /Ogtp
    ;   COMDAT ?TestC@@YAXXZ
    _TEXT   SEGMENT
    ?TestC@@YAXXZ PROC                  ; TestC, COMDAT
    ; File e:\r\playground\temp\consoleapplication2\consoleapplication2.cpp
    ; Line 32
        ret 0
    ?TestC@@YAXXZ ENDP                  ; TestC
    _TEXT   ENDS
    ; Function compile flags: /Ogtp
    ;   COMDAT _main
    _TEXT   SEGMENT
    _main   PROC                        ; COMDAT
    ; File e:\r\playground\temp\consoleapplication2\consoleapplication2.cpp
    ; Line 37
        xor eax, eax
    ; Line 38
        ret 0
    _main   ENDP
    _TEXT   ENDS
    END
    

    生成自:

    // ConsoleApplication2.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    
    class MyType {
        int _a, _b, _c;
    public:
        MyType(int a, int b, int c) : _a(a), _b(b), _c(c) {}
        MyType operator+(MyType & op) {/* do something */ }
    };
    
    struct MyTypeC {
        int a; int b; int c;
    };
    
    void f(MyType & mt) { mt; return; }
    void g(MyTypeC & mtc) { mtc; return; }
    
    void TestCpp() {
        for (int i = 100000; --i; ) {
            MyType mt(0, 1, 2);
            f(mt);
        }
    }
    
    void TestC() {
        for (int i = 100000; --i; ) {
            MyTypeC mtc = { 0,1,2 };
            g(mtc);
        }
    }
    int main()
    {
        TestCpp();
        TestC();
        return 0;
    }
    

答案 1 :(得分:0)

您是否观察到实际差异?除非样本中没有显示隐藏的成本,例如虚拟构造函数或方法,否则它们将生成相同的机器代码。在C ++中,structclass之间唯一真正的区别是前者为成员建立了默认的public范围,而后者建立了默认的private范围。