#include <iostream>
#include <string>

using namespace std;

template<class T> class Sample {
private:
 T val;
public:
 Sample(T InitialVal=T()) : val(InitialVal)
 {
    // do nothing
 }
 ~Sample() 
 {
    // do nothing
 }
 void PrintVal(void)
 {
     try {
    cout << "[" << val << "]" << endl;
     } catch(...) {
        cout << "exception thrown" << endl;
     }
 }
};

int main() {
    // your code goes here
    Sample<int> ints(20), intd;
    Sample<char *> chars(const_cast<char*>("Neelakantan")), charsd;
    Sample<string> s, ss("neel");

    ints.PrintVal();
    intd.PrintVal();

    chars.PrintVal();
    charsd.PrintVal(); // <<- Culprit line. Commenting out this line works as expected.

    s.PrintVal();
    ss.PrintVal();

    return 0;
}

Kiedy uruchomię powyższy kod, otrzymuję poniższy wyjście:

sh-4.4$ g++ -o main *.cpp                                                                                                                                                       
sh-4.4$ main                                                                                                                                                                    
[20]                                                                                                                                                                            
[0]                                                                                                                                                                             
[Neelakantan]                                                                                                                                                                   
[sh-4.4$

Kiedy komentuję linię "charsd.PrintVal();", otrzymuję poniższy wyjście:

[sh-4.4$ g++ -o main *.cpp                                                                                                                                                      
sh-4.4$ main                                                                                                                                                                    
[20]                                                                                                                                                                            
[0]                                                                                                                                                                             
[Neelakantan]                                                                                                                                                                   
[]                                                                                                                                                                              
[neel]                                                                                                                                                                          
sh-4.4$

Jaki jest problem z obiektem "CharSd" instancji szablonu typu próbki typu ? Nie został wyrzucony wyjątku.

Wersja kompilatora:

sh-4.4$ g++ --version                                                                                                                                                           
g++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)                                                                                                                                      
Copyright (C) 2017 Free Software Foundation, Inc.                                                                                                                               
This is free software; see the source for copying conditions.  There is NO                                                                                                      
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                                                                                                     

sh-4.4$
0
Neelakantan K 5 czerwiec 2018, 12:30

3 odpowiedzi

Najlepsza odpowiedź

[Zmieniona odpowiedź na podstawie nowych informacji / wiedzy. Zobacz także odpowiedź Jonathana Wakeleya (zaktualizowałem to, zanim to zobaczyłem), który jest współpracownikiem GCC / libstdc ++ i który odebrał raport o błędach, który złożyłem. Dziękujemy dla niego za stawianie mnie prostych i najszczerszych przeprosin za uczynienie absurdalnego założenia, że ostream byłoby zachowywać się w sposób wcześniej opisany w pierwszej kolejności.]

W rzeczywistości robisz, w punkcie niepowodzenia, jest w mocy, to:

std::cout << (const char *) nullptr << std::endl;

I czego większość ludzi spodziewa się zdobyć (choć ściśle mówiąc o zachowaniu tego, co robisz, jest niezdefiniowany) byłby segfault.

libstdc++, Jednak, który zawiera jednak wdrożenie ostream, że używa gcc, robi coś innego. Ustawia badbit na strumieniu, a tylko wtedy, gdy włączyłeś wyjątki badbit Wyjątki (które są domyślnie wyłączone) Czy to (także) wyrzucić wyjątek. Dziękuję Jonathan Wakeley za wskazanie do mnie, kiedy złożyłem raport o tym, nic o tym nie wiedziałem (i nikt inny nie opublikował do tego wątku, najwyraźniej), kiedy opublikowałem pierwszą wersję tej odpowiedzi.

Ale twój kod nie włączony jest wspomniane wyjątki, więc wszystko, co się dzieje, jest to, że badbit zostaje ustawiony na cout i wszystkie kolejne pisze następnie cicho zawiedzie. Wcześniej błędnie zinterpretowałem to jako program cicho wychodzący, gdy Nullptr został przekazany, ale myliłem się, a ja przepraszam deweloperów za nieuzasadnione założenie. W komentarzach jest coś więcej.

Aby uzyskać wyjątek wyrzucony, gdy tak się stanie, musisz włączyć wyjątek badbit na strumieniu, który możesz to zrobić:

std::cout.exceptions (std::ostream::badbit | std::ios::failbit);

Wtedy masz wyjątek, na który miałeś nadzieję. Osobiście nie podoba mi się wiele zachowań, wolałbym mieć segfault (i faktycznie, z krzywką, Robisz), ale Jonathan mówi mi, że był taki sposób od 2002 roku, a deweloperzy mają dobre powody, by go teraz zmienić.

Jest nowy Demo na żywo pokazując zachowanie gcc z powyższą linią dodaną i Wyjście jest teraz:

[20]
[0]
[Neelakantan]
terminate called after throwing an instance of 'std::__ios_failure'
  what():  basic_ios::clear: iostream error
[
Aborted

Więc ostrzegany, pułapka na nieostrożne kłamstwa w oczekiwaniu: "Dlaczego nie ma nagle żaden z moich oświadczeń logowania?", Albo coś takiego.

1
Paul Sanders 16 lipiec 2018, 21:15

Problem polega na tym, że obiekt val; charsd jest inicjowany za pomocą zerowego wskaźnika. Więc spróbuj przekazać go do operator << narusza warunek wstępny i powoduje niezdefiniowane zachowanie.

5
user7860670 14 czerwiec 2018, 08:36

charsd zawiera wskaźnik zerowy i pisanie null const char* do ostream jest niezdefiniowane zachowanie.

Wdrożenie standardowych kontroli biblioteki standardowej dla tego stanu (patrz Kod tutaj) i ustawia flagę badbit w stanie strumienia. badbit wskazuje, że stan strumienia został uszkodzony, w tym przypadku przez nieoczekiwany wskaźnik zerowy, który mówi standard, jest niezdefiniowany zachowanie. N.B. Ta obsługa wskaźników zerowych dla ostream nie jest udokumentowana i może się zmienić w przyszłości.

Program nadal biegnie do zakończenia, ale dlatego, że badbit jest ustawiony na strumieniu, wszystkie pisze pisze niepowodzenie, wytwarzając więcej wyjścia na std::cout.

Program nie tylko wyjdzie po milczeniu, gdy wskaźnik NULL jest zapisany do strumienia . Ustawia flagę błędu i kontynuuje pracę.

Jeśli chcesz wykryć, że możesz to zrobić, na przykład, sprawdzając stan strumienia na końcu {x0}} i drukowania wiadomości do standardowego błędu:

int main() {
    // ...

    if (!std::cout)
        std::cerr << "An error happened while writing to cout\n";

    return 0;
}

Lub mówiąc strumień cout, który chcesz przekształcić błędy w wyjątki:

int main() {

    std::cout.exceptions(std::ios::badbit | std::ios::failbit);

    // ...

    return 0;
}

Teraz program rzuci wyjątek, gdy tylko błąd nastąpi:

terminate called after throwing an instance of 'std::ios_base::failure[abi:cxx11]'
  what():  basic_ios::clear: iostream error
Aborted (core dumped)
3
Jonathan Wakely 13 czerwiec 2018, 19:59