代码之家  ›  专栏  ›  技术社区  ›  Peter VARGA

初始化每个类成员时的性能问题?

  •  0
  • Peter VARGA  · 技术社区  · 7 年前

    我认为这个问题是关于初始化的一般观点,它已经回答了很多问题:

    Should constructor initialize all the data members of the class?

    但是,当我的类有100个成员,我用 {} 命令,只是因为Eclipse警告我未初始化的成员:

    未在此构造函数中初始化成员“foo”

    我的问题: 每次实例化此类时,对具有大量成员[>50]的类中的每个成员进行初始化是否会导致性能问题?

    更新: 由于第一条评论:我一般都在问。Eclipse在我的项目中警告我9次,分为4个类!

    1 回复  |  直到 7 年前
        1
  •  -1
  •   Peter VARGA    7 年前

    这里是我用gcc运行它的结果。

    我用不同数量的类成员测试了它(5次,取平均值),但用了100000个类的实例化。

    这有点棘手,因为我使用了最高的优化级别 -O3 因此,我必须避免编译器优化代码。

    拥有100名班级成员:

    Initialized class members:      4'484 msec
    Not initialized class members:     50 msec
    

    拥有25名班级成员:

    Initialized class members:      1'146 msec
    Not initialized class members:     50 msec // as expected it didn't change
    

    拥有500名班级成员:

    Initialized class members:     22'129 msec
    Not initialized class members:     50 msec // as expected it didn't change
    

    我的结论是:

    有- 在正常情况下 - 初始化所有类成员时会出现显著的性能问题。具有 在正常情况下 我的意思是,当有一个函数[与其他代码一起]进行了100000次迭代时,成员初始化实际上并不算数。

    正如评论中所述,一个好的设计不应该有那么多的班级成员——我只是好奇而已。


    PS:

    我检查了汇编程序列表,当然,在初始化版本中,gcc初始化了每个 int 具有的成员 movq $0, 40(%rsp) -the 40 是堆栈上的位置。


    #include <stdlib.h>
    #include <stdio.h>
    #include <chrono>
    #include <ctime>
    #include <utility>
    
    template<typename TimeT = std::chrono::microseconds>
    class measure
    {
    public:
        template<typename F, typename ...Args>
        static typename TimeT::rep execution(F func, Args&&... args)
        {
            auto start = std::chrono::system_clock::now();
            func(std::forward<Args>(args)...);
            auto duration = std::chrono::duration_cast< TimeT> 
                                    (std::chrono::system_clock::now() - start);
    
            return duration.count();
        }
    };
    
    class foo
    {
       // for uninitialized version remove the {}
       size_t mainValue {};
       size_t classMember0 {};
       ...
       size_t classMember499 {};
    
    public:
        foo( size_t value ) : mainValue (value + 4660) {};
        auto getMainValue() -> size_t { return mainValue; };
    };
    
    auto runCode( size_t iterationCount ) -> void
    {
        size_t someValue {};
        for ( size_t j = 0 ; j < iterationCount ; ++j )
        {
            foo MyFoo (iterationCount);
            someValue += MyFoo.getMainValue();
        }
        printf( "Result=%ld\n", someValue );   // that the whole code isn't optimized away...
    }
    
    int main( int argc, char * argv [] )
    {
        if ( argc != 2 )
        {
            printf( "Usage: %s <Start-Value>\n", argv [0] );
            return 0;
        }
    
        size_t variableValue = (size_t) atof( argv [1] );
        auto threadExecutionTime = measure<>::execution( [&] () { runCode( variableValue ); } );
    
        printf( "Total execution time was %.3f milliseconds. %s",
                    threadExecutionTime / 1000. );
    }