2

次のコードを検討してください。

#include <iostream>
#include <type_traits>

class Base
{
    public: static int f() {return 42;}
};

class Derived : public Base
{
    protected: int x;
};

class NotDerived
{
    protected: int x;
};

int main()
{
    std::cout<<sizeof(Base)<<std::endl;
    std::cout<<sizeof(Derived)<<std::endl;
    std::cout<<sizeof(NotDerived)<<std::endl;
    return 0;
}

g++ 4.7 -O3 を使用すると、次のように出力されます。

1
4
4

それをよく理解していれば、空の基本クラスの最適化が有効になっていることを意味します。

しかし、私の質問は実行時のオーバーヘッドに関するものです。対応するオブジェクトを構築/破棄する必要があるため、Derivedオブジェクトと比較してオブジェクトを作成(および破棄)するオーバーヘッドはありますか?NotDerivedDerivedBase

4

3 に答える 3

3

標準はそれを保証するものではありませんが、これらの場合に何か違うことをしたコンパイラにはわずかな欠陥があると考えています。

ベースを初期化するために文字通り何もする必要はありません。メモリを初期化する必要はなく、仮想呼び出しメカニズムを設定する必要もありません。そのためのコードは生成されません。

ただし、これが本当に重要な場合は、重要な設定でアセンブリを常にチェックする必要があります。

于 2012-12-18T00:15:09.843 に答える
2

標準はセマンティクスのみを指定しているため、これに対する答えは実装に依存します。

ただし、最新のコンパイラと最適化をオンにすると、まったく違いが見られないと思います。

余分なメモリを割り当てる必要も、実行する余分なコードもありません。余分なベースは仮想ではないため、構築中に vtable ポインタを変更する必要もありません。あなたDerrivedNotDerrivedコンストラクターは、命令ごとに同一である可能性があります。

すべての最適化をオフにすると、一部のプラットフォームで空のBase::Base()関数が呼び出される可能性がありますが、最適化されていないビルドのパフォーマンスについて心配する必要はありません。


gcc.godbolt.org に小さなデモをまとめました: http://tinyurl.com/cg8ogym

要するに

    extern void marker______________________________________();
    // ... 
    marker______________________________________();
    new NotDerived;
    marker______________________________________();
    new Derived;
    marker______________________________________();

にコンパイルします

call    marker______________________________________()@PLT
movl    $4, %edi
call    operator new(unsigned long)@PLT
call    marker______________________________________()@PLT
movl    $4, %edi
call    operator new(unsigned long)@PLT
call    marker______________________________________()@PLT

それをclangに切り替えると、メモリ割り当ても最適化されます

于 2012-12-18T00:13:39.903 に答える
0
#include <type_traits>
#include <unistd.h>

class SlowBase
{
    SlowBase() { ::sleep(5); }

    public: static int f() {return 42;}
};
static_assert( std::is_empty<SlowBase>::value , "SlowBase is empty" );

Baseクラスの構築には 5 秒かかります!!

#include <type_traits>

class FatBase
{
    FatBase() = default;
    int data[1024*1024];    
    public: static int f() {return 42;}
};
static_assert( !std::is_empty<FatBase>::value , "FatBase is not empty" );

しかし、これは時間がかかりません!

私の要点は、構築のオーバーヘッドはクラスの大きさとは関係がなく、コンストラクターの動作に関係しているということですSlowBaseは空のクラスですが、構築に非常に時間がかかります。FatBaseサイズはメガバイトですが、配列要素をゼロにすることさえしないので、何もしません。

あなたのBase例では、暗黙的に宣言された自明なデフォルトコンストラクターがあるため、何もしません。

于 2012-12-18T10:12:04.143 に答える