Czy kompilator może optymalizować prywatne elementy składowe danych?

Dec 08 2020

Jeśli kompilator może udowodnić, że (prywatny) element członkowski klasy nigdy nie jest używany, w tym przez potencjalnych przyjaciół, to czy standard pozwala kompilatorowi na usunięcie tego elementu członkowskiego z pamięci klasy?

Jest oczywiste, że nie jest to możliwe dla członków chronionych lub publicznych w czasie kompilacji, ale mogą zaistnieć okoliczności, w których możliwe jest skonstruowanie takiego dowodu w odniesieniu do prywatnych członków danych.


Powiązane pytania:

  • Za kulisami publicznego, prywatnego i chronionego (wywołało to pytanie)
  • Czy kompilator C ++ może optymalizować niereferencyjne obiekty lokalne (dotyczące obiektów automatycznych)
  • Czy zmienna statyczna zawsze będzie zużywać pamięć? (o obiektach statycznych)

Odpowiedzi

31 PeterCordes Dec 08 2020 at 23:19

Możliwe w teorii (wraz z nieużywanymi członkami publicznymi), ale nie z rodzajem ekosystemu kompilatora, do którego jesteśmy przyzwyczajeni (celowanie w stały ABI, który może łączyć oddzielnie skompilowany kod). Usunięcie nieużywanych członków można było wykonać tylko z optymalizacją całego programu, która zabrania oddzielnych bibliotek 1 .

Inne jednostki kompilacji mogą wymagać uzgodnienia sizeof(foo), ale nie byłoby to coś, co można by wyprowadzić z a, .hgdyby polegało to na sprawdzeniu, że żadna implementacja zachowania funkcji składowej nie zależy od jakichkolwiek prywatnych elementów członkowskich.

Pamiętaj, że C ++ tak naprawdę określa tylko jeden program, a nie sposób na tworzenie bibliotek. Język określony w ISO C ++ jest zgodny ze stylem implementacji, do którego jesteśmy przyzwyczajeni (oczywiście), ale możliwe są implementacje, które pobierają wszystkie pliki .cppi .hna raz i tworzą pojedynczy, niezależny, nierozszerzalny plik wykonywalny.

Jeśli wystarczająco ograniczysz implementację (brak ustalonego ABI), możliwe stanie się agresywne stosowanie reguły as-if w całym programie.


Przypis 1: Chciałem dodać „ lub w jakiś sposób wyeksportować informacje o rozmiarze do innego kompilowanego kodu ” jako sposób na zezwolenie na biblioteki, jeśli kompilator mógł już zobaczyć definicje dla każdej funkcji składowej zadeklarowanej w klasie. Ale odpowiedź @ PasserBy wskazuje, że oddzielnie skompilowana biblioteka może być tym, co wykorzystywało zadeklarowanych członków prywatnych w sposób, który ostatecznie wywołuje widoczne zewnętrznie efekty uboczne (takie jak I / O). Musielibyśmy więc w pełni je wykluczyć.

W związku z tym członkowie publiczni i prywatni są równoważni do celów takiej optymalizacji.

17 KonradRudolph Dec 08 2020 at 22:26

Jeśli kompilator może udowodnić, że (prywatny) element członkowski klasy nigdy nie jest używany

Kompilator nie może tego udowodnić, ponieważ prywatne elementy członkowskie mogą być używane w innych jednostkach kompilacji. Konkretnie, jest to możliwe w kontekście wskaźnika do elementu członkowskiego w argumencie szablonu zgodnie z [temp.spec] / 6 standardu, jak pierwotnie opisał Johannes Schaub .

Podsumowując: nie, kompilator nie może optymalizować prywatnych członków danych bardziej niż członków publicznych lub chronionych (z zastrzeżeniem reguły as-if).

11 PasserBy Dec 08 2020 at 22:30

Nie, ponieważ możesz legalnie podważyć system kontroli dostępu .

class A
{
    int x;
};

auto f();

template<auto x>
struct cheat
{
    friend auto f() { return x; }
};

template struct cheat<&A::x>;  // see [temp.spec]/6

int& foo(A& a)
{
    return a.*f();  // returns a.x
}

Biorąc pod uwagę, że kompilator musi naprawić ABI, gdy Ajest używany po raz pierwszy i nigdy nie może wiedzieć, czy jakiś przyszły kod może uzyskać dostęp x, musi naprawić pamięć, Aaby zawierać x.