nanoant20 Temat założony przez niniejszego użytkownika |
rzucanie wyjątkiem throw std::bad_array_new_length » 2024-03-05 11:11:03 w klasie "mySolution" staram się złapać wyjątek, gdy zostaną podane "Nieprawidłowe wymiary tablicy", ale to nie działa. Dziękuję za pomoc. #include <iostream> #include <cstdlib> #include <iomanip> #include <random> #include <stdexcept> using namespace std;
class mySolution { private: int * * tab; int rowCount; int colCount; constexpr static int MIN = 7; constexpr static int MAX = 777; std::random_device rd; std::default_random_engine eng { rd() }; std::uniform_int_distribution < int > distr { MIN, MAX }; public: mySolution() { cout << "Konstruktor domyslnny bezparametrowy" << '\n'; this->tab = new int *[ 1 ] { nullptr }; for( unsigned int i = 0; i < 1; ++i ) tab[ i ] = new int[ 1 ] { 0 }; this->tab = nullptr; this->rowCount = 0; this->colCount = 0; } mySolution( int rows, int cols ) : rowCount( rows ) , colCount( cols ) { try { if( rowCount <= 0 || colCount <= 0 ) { throw std::bad_array_new_length { }; } cout << "Konstruktor domyslnny" << '\n'; this->tab = new int *[ rowCount ] { nullptr }; for( int i = 0; i < rowCount; ++i ) tab[ i ] = new int[ colCount ] { 0 }; } catch( const std::bad_array_new_length & ) { cerr << "Nieprawidlowe wymiary tablicy!" << endl; this->tab = nullptr; } this->rowCount = rowCount; this->colCount = colCount; } int size_rowCount() const { return this->rowCount; } int size_colCount() const { return this->colCount; } ~mySolution() { if( tab != nullptr ) { for( int i = 0; i < rowCount; ++i ) delete[ ] tab[ i ]; delete[ ] tab; } cout << "~Destructor" << '\n'; }; void fill_tab() { for( int i = 0; i < rowCount; ++i ) { for( int j = 0; j < colCount; ++j ) { tab[ i ][ j ] = distr( eng ); } } } void display() const { for( int i = 0; i < rowCount; ++i ) { cout << "Pole position " << i << setw( 4 ) << std::setfill( ' ' ) << right << "\t"; for( int j = 0; j < colCount; ++j ) { cout << setw( 4 ) << std::setfill( ' ' ) << right << tab[ i ][ j ] << " "; } cout << "\n"; } } };
auto main()->int { int iW { 0 }, iK { 0 }; while(( cout << "Ile wierszy : " ) &&( cin >> iW ) &&( cout << "Ile kolumn : " ) &&( cin >> iK ) ) { try { mySolution tab( iW, iK ); tab.display(); tab.fill_tab(); cout << endl; tab.display(); cout << '\n'; } catch( const std::bad_array_new_length & ) { std::cerr << "Blad tworzenia obiektu mySolution!" << std::endl; } } return 0; }
|
|
DejaVu |
» 2024-03-05 11:24:28 catch( const std::bad_array_new_length & ) { W konstruktorze złapałeś wyjątek i wypisałeś komunikat, więc nie złapiesz go 'dalej'. Jeżeli chcesz go 'łapać' później to powinieneś wywalić try/catch które masz w konstruktorze. /edit: Jeszcze trochę 'wskazówek' odnośnie rzucania wyjątków w konstruktorze (ChatGPT): Rzucanie wyjątków w konstruktorze klasy w C++ jest uznawane za akceptowalną i czasami niezbędną praktykę, szczególnie w sytuacjach, gdy podczas inicjalizacji obiektu napotykany jest błąd, który uniemożliwia poprawne stworzenie lub skonfigurowanie obiektu. Oto kilka kluczowych punktów, które należy wziąć pod uwagę:
1. **Zarządzanie błędami**: Rzucanie wyjątku z konstruktora jest skutecznym sposobem na sygnalizowanie, że obiekt nie został poprawnie utworzony z powodu wystąpienia pewnych problemów. Dzięki temu mechanizmowi wyjątków można przerwać proces tworzenia obiektu i poinformować wywołującego o napotkanym problemie.
2. **Zasoby i bezpieczeństwo**: Jeśli konstruktor alokuje zasoby (np. pamięć, pliki, połączenia sieciowe), które wymagają późniejszego zwolnienia lub zamknięcia, rzucenie wyjątku może być jedynym sposobem na uniknięcie wycieków zasobów w przypadku, gdy inicjalizacja nie może być dokończona pomyślnie. C++ nie wywoła destruktora obiektu, jeśli konstruktor tego obiektu nie zakończy się pomyślnie, więc odpowiedzialność za posprzątanie w takiej sytuacji leży po stronie konstruktora lub mechanizmów, które go otaczają.
3. **RAII (Resource Acquisition Is Initialization)**: Idiom RAII jest powszechnie stosowany w C++ do zarządzania zasobami, gdzie zasoby są alokowane w konstruktorze i zwalniane w destruktorze. Rzucanie wyjątku w konstruktorze jest zgodne z tym idiomem, ponieważ sygnalizuje, że zasób nie został poprawnie zdobyty i obiekt nie powinien być używany.
4. **Poprawne projektowanie i dokumentacja**: Podczas korzystania z wyjątków w konstruktorze ważne jest, aby dokładnie zaprojektować interfejsy klas i odpowiednio dokumentować zachowanie konstruktorów. Użytkownicy klasy powinni być świadomi potencjalnych wyjątków, które mogą zostać rzucone, oraz powodów, dla których mogą one wystąpić.
5. **Zarządzanie wyjątkami**: Należy odpowiednio obsługiwać wyjątki rzucone przez konstruktory, co oznacza użycie bloków `try` i `catch` tam, gdzie obiekty są tworzone. Pozwala to na eleganckie zarządzanie błędami i zapobiega niespodziewanemu zakończeniu programu.
Podsumowując, rzucanie wyjątków w konstruktorach w C++ jest praktyką, która ma swoje miejsce, szczególnie gdy chodzi o informowanie o błędach inicjalizacji i zarządzanie zasobami. Ważne jest jednak, aby robić to rozważnie i zawsze dostarczać użytkownikom klasy wystarczająco dużo informacji, aby mogli odpowiednio reagować na wyjątki. |
|
nanoant20 Temat założony przez niniejszego użytkownika |
» 2024-03-05 13:31:10 @DejaVu zrobiłem tak jak zasugerowałeś, Jeżeli chcesz go 'łapać' później to powinieneś wywalić try/catch które masz w konstruktorze. ale teraz mam problem gdy, user wprowadzi wartość 0 (słownie zero). Wywala debug'er: Debug Error: HEAP CORRUPTION DETECTED: after Normal block (#202) at 0x0000025744DF7030. CTR Detected that the application wrote to memory after andof heap buffer.
aktualny listing na którym to się dzieje #include <iostream> #include <cstdlib> #include <iomanip> #include <random> #include <stdexcept> using namespace std;
class mySolution { private: int * * tab; int rowCount; int colCount; constexpr static int MIN = 7; constexpr static int MAX = 777; std::random_device rd; std::default_random_engine eng { rd() }; std::uniform_int_distribution < int > distr { MIN, MAX }; public: mySolution() { cout << "Konstruktor domyslnny bezparametrowy" << '\n'; this->tab = new int *[ 1 ] { nullptr }; for( unsigned int i = 0; i < 1; ++i ) tab[ i ] = new int[ 1 ] { 0 }; this->tab = nullptr; this->rowCount = 0; this->colCount = 0; } mySolution( int rows, int cols ) : rowCount( rows ) , colCount( cols ) { if( rowCount <= 0 || colCount <= 0 ) { cerr << "Nieprawidlowe wymiary tablicy!" << endl; this->tab = nullptr; } cout << "Konstruktor domyslnny" << '\n'; this->tab = new int *[ rowCount ] { nullptr }; for( int i = 0; i < rowCount; ++i ) tab[ i ] = new int[ colCount ] { 0 }; this->rowCount = rowCount; this->colCount = colCount; } int size_rowCount() const { return this->rowCount; } int size_colCount() const { return this->colCount; } ~mySolution() { if( tab != nullptr ) { for( int i = 0; i < rowCount; ++i ) delete[ ] tab[ i ]; delete[ ] tab; } cout << "~Destructor" << '\n'; }; void fill_tab() { for( int i = 0; i < rowCount; ++i ) { for( int j = 0; j < colCount; ++j ) { tab[ i ][ j ] = distr( eng ); } } } void display() const { for( int i = 0; i < rowCount; ++i ) { cout << "Pole position " << i << setw( 4 ) << std::setfill( ' ' ) << right << "\t"; for( int j = 0; j < colCount; ++j ) { cout << setw( 4 ) << std::setfill( ' ' ) << right << tab[ i ][ j ] << " "; } cout << "\n"; } } };
auto main()->int { int iW { 0 }, iK { 0 }; while(( cout << "Ile wierszy : " ) &&( cin >> iW ) &&( cout << "Ile kolumn : " ) &&( cin >> iK ) ) { try { mySolution tab( iW, iK ); tab.display(); tab.fill_tab(); cout << endl; tab.display(); cout << '\n'; } catch( const std::bad_array_new_length & ) { std::cerr << "Blad tworzenia obiektu mySolution!" << std::endl; } } return 0; }
|
|
DejaVu |
» 2024-03-05 13:33:38 Za dużo wyciąłeś kodu. if( rowCount <= 0 || colCount <= 0 ) { throw std::bad_array_new_length { }; }
Ta linijka jest potrzebna - tj. rzucasz wyjątek, że są złe parametry, a w mainie przechwytujesz wyjątek. |
|
nanoant20 Temat założony przez niniejszego użytkownika |
» 2024-03-05 13:37:59 @DejaVu Dziękuję. Zadziałało, tak jak należy. |
|
« 1 » |