2017-01-16 13 views
9

Załóżmy, że klasa ma żadnych danych:Wielkość klasy podstawowej klasy środka pochodzącego

struct Empty { 
    /*some methods here*/ 
}; 

I klasy pochodnej

struct Derived: Empty { 
    int a; 
    int b; 
    char c; 
    .... 
}__attribute__((packed));` 

obiektów pustych grupy mają wielkość = 1. Pusty element klasy uzyskanego zwykle ma 0 rozmiar. Jak rozumiem kompilator, zobacz, że klasa Base Empty nie ma żadnych danych, więc może zoptymalizować rozmiar Empty w przypadku, gdy jest "w środku" Pochodnym, ale nie jest to wymagane przez standard.

Więc pytanie brzmi:

można jakoś określić w czasie kompilacji, które Empty część pochodnych klasy naprawdę nie zajmują pamięci.

Rozumiem, że mogę sprawdzić np. sizeof(Derived) = sizeof(a) + sizeof(b) ... Ale jest zbyt szczegółowe i istnieje kilka klas takich jak pochodne. Czy istnieje bardziej eleganckie rozwiązanie?

+0

Dlaczego chcesz to wiedzieć? Zauważ, że element członkowski lub klasa podstawowa może zajmować pamięć bez dodawania do footprintu klasy pochodnej (przez użycie spacji zagubionej do dopełnienia). Zauważ też, że 'sizeof' na struct może być mniejszy lub większy niż suma' sizeof' tego elementu i zasad. – skyking

+0

Mam zamiar użyć tych klas pochodnych do reprezentowania niektórych danych sieciowych. Więc wszystkie takie klasy pochodne będą miały atrybut spakowany. Przejdę również do dziedziczenia z jakiejś klasy szablonów, aby zaimplementować Ciekawe powtarzające się wzorce szablonów. Aby wszystkie klasy pochodne miały pewną wspólną funkcjonalność. Jednak nie chcę, aby to dziedzictwo miało wpływ na układ klas pochodnych. –

Odpowiedz

11

Można użyć std::is_empty, aby upewnić się, że klasa dziedziczy z ty jest zero-size:

static_assert(std::is_empty<Empty>{}); 

Jeśli tak jest, empty base optimization jest guaranteed to take place for standard-layout classes.


Rozumiem, że nie mogę sprawdzić jak sizeof(Derived) = sizeof(a) + sizeof(b) ... ale jest zbyt rozwlekły. Czy istnieje bardziej eleganckie rozwiązanie?

To nie działa poprawnie, ponieważ trzeba wziąć pod uwagę wyściółkę i ewentualne atrybuty, takie jak packed.

+0

Dzięki. Nie wiedziałem, że ta optymalizacja jest gwarantowana. –

+0

Standard nie gwarantuje tej optymalizacji. Jest to dość powszechne w praktyce, chociaż w kompilatorach rzeczywistych. – Peter

+1

@Peter: [jest gwarantowany dla * standardowych układów * klas] (http://stackoverflow.com/questions/10788823/is-the-empty-base-class-optimization-now-a-mates-optymizacja-at -least-for). Wyjaśnię moją odpowiedź. –

3

Można użyć więcej "starych" (przed C++ 11) makro - offsetof:

struct Empty {}; 
struct NonEmpty { 
    int a; 
}; 
struct Derived1: Empty { 
    int a; 
    int b; 
    char c; 
}; 
struct Derived2: NonEmpty { 
    int a; 
    int b; 
    char c; 
}; 
static_assert(offsetof(Derived1,a) == 0,""); 
static_assert(offsetof(Derived2,a) != 0,""); 

Można użyć tego makra aby sprawdzić kolejność zmiennych składowych też:

static_assert(offsetof(Derived,a) < offsetof(Derived,b),""); 
static_assert(offsetof(Derived,b) < offsetof(Derived,c),""); 

Ale nie zapomnij - offset ma takie samo ograniczenie:

Jeśli typ nie jest standardowy typ układu, zachowanie jest niezdefiniowane. Jeśli element członkowski jest elementem statycznym lub członkiem, zachowanie jest niezdefiniowane.

Powiązane problemy