Czy kompilator może optymalizować prywatne elementy składowe danych?
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
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, .h
gdyby 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 .cpp
i .h
na 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.
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).
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 A
jest 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ęć, A
aby zawierać x
.