2015-05-04 40 views
12

Google C++ Style Guide stany żezmienić znaczenie kodu przez zastąpienie deklaracji z przodu obejmują

W skrajnych przypadkach zastąpienie #include z przodu deklaracji mogą dyskretnie zmienić znaczenie kodu.

Czy możesz mi pomóc znaleźć przykłady?

+1

Nie mogę wymyślić żadnych przypadków, w których to zamienia ważny program na inny ważny program o innym znaczeniu. Ale może to łatwo doprowadzić do cichego wyświetlania programu niezdefiniowanych zachowań. Na przykład. "** 5.3.5/5 ** Jeśli usunięty obiekt ma niekompletny typ klasy w punkcie usunięcia, a cała klasa ma nietrywialny destruktor lub funkcję dealowania, zachowanie jest niezdefiniowane." –

+0

@IgorTandetnik Czy możesz przekonwertować komentarz na odpowiedź, najlepiej za pomocą małego przykładu kodu? – Peter

+0

ilekroć liczy się, czy dany typ jest kompletny, czy nie ma to znaczenia. – Walter

Odpowiedz

7

Oto dwa przypadki. Jednym z nich jest UB, drugi myślę definiuje zmianę zachowań (zakładając brak ODR lub podobnych naruszeń: to znaczy, nikt nie zadzwonił do foo kiedykolwiek widzi definicję A, ale nie jestem pewien)

namespace N { 
    struct B {}; 
    struct A;//:B{}; 
} 

void foo(N::B*){ 
    std::cout << "B\n"; 
} 
template<class T, class=std::enable_if_t<!std::is_convertible<T*,N::B*>{}>> 
void foo(T*){ 
    std::cout << "T\n"; 
} 

int main() { 
    foo((N::A*)0); 
} 

zastępując struct A; z struct A:B{}; zmieni, które z przeciążeń foo są wywoływane.

Ponadto delete A; zadzwoni pod numer ~A(), jeśli jest widoczny, gdy zostanie wywołane delete A;. W przeciwnym razie, jeśli istnieje nietrywialny destruktor, mamy UB. W tym przypadku znaczenie kodu zmienia się w to, że przechodzi od UB do DB, co jest chyba zmianą znaczenia.

3

Jednym z najbardziej podstępnych przykładów, o których wiem, jest obsada w stylu C w połączeniu z dziedziczeniem.

Powiedzmy, że masz:

class Parent1 {}; 
class Parent2 {}; 

class Child : public Parent1, public Parent2 {}; 

Potem w jakiś inny plik rzucasz z Parent2 do dziecka:

Parent2* parent2_ptr = new Child; 
Child* obj = (Child*)parent2_ptr; 

Z pełną definicję oddanych C-styl to static_cast, poprawnie naprawek adres. Z deklaracją forward (z Child) obsada w stylu C staje się reinterpret_cast cicho łamiącą kod.