2017-12-24 115 views
11

W rzeczywistości błąd segmentacji występuje w innym programie, który próbowałem skompilować, co dzieje się z powodu tego zachowania.Delegowanie konstruktora daje błąd segmentacji przy użyciu pola klasy dla argumentu

Moje pytanie brzmi:

Jest to bug czy moja wina?

Powtarzalne w jakikolwiek sposób (nawet jeśli pole something są prywatne lub chronione) i tu jest mój przykład:

main.cc:

#include <iostream> 
class Test { 
    public: 
     const char* something = "SOMETHING HERE!!!"; 
     Test(const int& number) : Test(something, number) { } 
     // XXX: changed `something` to `_something` to make it different 
     Test(const char* _something, const int& number) { 
      std::cout << _something << std::endl; 
      std::cout << number << std::endl; } 
     ~Test() { } 
}; 

int main(int argc, char* argv[]) { 
    Test te1(345); 
    Test te2("asdasdad", 34523); 
    return 0; 
} 

I tu jest to, co się dzieje, gdy Kompilacja z:

g++ main.cc -Os -o main 

i uruchamiana z:

./main 

wyjście jest:

[email protected]:~/ $ ./main 
A"�~ <-- this is random 
345 
asdasdad 
34523 

Ale kiedy umożliwiają optymalizację z -O0 lub -O1 lub -O2 ... wyjście jest tylko nowa linia:

[email protected]:~/ $ ./main 
[email protected]:~/ $ 

G ++ wersja:

[email protected]:~/ $ g++ --version 
g++ (Raspbian 6.3.0-18+rpi1) 6.3.0 20170516 
+0

W następnym wierszu 'const char * something =" COŚ TUTAJ !!! ";" czy miałeś na myśli 'coś"? Jeśli nie, to ta zmienna nie została ustawiona. – Mixhab

+0

Wszystko jest tak, jak to wyjaśniłem w treści pytania. –

+0

Dość interesujące. – 0x499602D2

Odpowiedz

20
const char* something = "SOMETHING HERE!!!"; 

Domyślny inicjator po prawej stronie jest, jak sama nazwa wskazuje, wykorzystywany tylko wtedy, gdy nie podano jawnego inicjalizatora na liście inicjalizacyjnej konstruktora. Spójrzmy na twoje:

Test(const int& number) : Test(something, number) { } 

OK, delegujemy do innego konstruktora. Ten inny konstruktor wykona pełną inicjalizację, więc domyślny inicjator nie jest używany. Ale ... przekazujemy niezainicjowaną wartość something jako parametr.

Test(const char* _something, const int& number) { /* ... */ } 

Uh-oh. Teraz próbujemy użyć wartości _something, która jest kopią something, która jest nieokreślona. Niezdefiniowane zachowanie i ogień.

Naprawdę nie należy przekazywać wartości elementu klasy jako parametru do jego konstruktora, chyba że masz nieskończony zapas ognioodpornych kur i jaj.


Zachowanie szukasz można uzyskać poprzez umieszczenie wartość domyślną w wywołaniu konstruktora Delegat:

Test(const int& number) : Test("SOMETHING HERE!!!", number) { } 

... lub utrzymanie go w specjalnej zmiennej statycznej:

static constexpr char *const defaultSomething = "SOMETHING HERE!!!"; 
Test(const int& number) : Test(defaultSomething, number) { } 
+1

Alternatywnie, prywatny domyślny konstruktor pozwala ci pisać: Test (const char * _something, const int i number): Test() {/ * ... * /} ' – Davislor

+1

" Naprawdę nie powinieneś przekazywać wartości członek klasy jako parametr swojego konstruktora, chyba że masz nieskończony zapas ognioodpornych kur i jaj. " - dobrze zrobione – sehe

15

To jest błąd lub moja wina?

Och, to twoja wina. Domyślny inicjator elementu jest używany tylko do zainicjowania obiektu członkowskiego w nie-delegującym konstruktorze. Według [class.base.init]/9, kopalnia nacisk:

W nieograniczającym delegowania konstruktora, czy dana potencjalnie wykonana podobiekt nie jest wyznaczony przez MEM inicjatora-id (w tym przypadku, gdy nie ma MEM inicjatora -Wykaz ponieważ konstruktor ma konstruktor-inicjator), a następnie

  • Jeżeli jednostka jest członkiem niestatycznych danych, który ma inicjator domyślny użytkownika i albo [...] jednostka jest inicjowane z jego domyślny inicjator członu określony w [dcl.ini t];

Więc something nie jest inicjowany kiedy przechodzą do konstruktora docelowej. Twój program ma niezdefiniowane zachowanie i idzie w popłoch.

+6

"Och, to twoja wina." - lol, bez litości: D – Quentin

+5

@Quentin - Cóż, OP zapytał: P – StoryTeller

+0

Dziękuję! Zaakceptowałem odpowiedź @ Quentina, ponieważ jest bardziej kompletna. –