Gage Temat założony przez niniejszego użytkownika |
Dziwne zachowanie programu » 2016-03-04 18:40:39 Witam! Przysiadłem dzisiaj do kompilatora w celu napisania jednego spośród programów podsumowujących dział "Przeładowanie operatorów" w "Symfonii C++". Wszystko szło dobrze, ale natknąłem się na pewien błąd, którego źródła nie potrafię zdefiniować. Do rzeczy - program uruchamia się, ale składnik "ktory_jestem" zmienia się po zdefiniowaniu kolejnego obiektu klasy. Przykładowo - po "powołaniu do życia" obiektu obiekt0, wartość obiekt0->ktory_jestem wynosi 0. Po zdefiniowaniu obiekt1 - wartość obiekt0->ktory_jestem jest ogromną wartością losową. Jedynie ostatni zdefiniowany obiekt klasy posiada wartość poprawną. Gdzie tutaj popełniłem błąd? Dziękuję za odpowiedzi i pozdrawiam! #include <iostream> using namespace std;
class obiekty { static int wywolan; static bool zarezerwowane[ 100 ]; string przedstawienie; static char * tablica[ 100 ]; static int ktory_statyczny; public: int ktory_jestem; static void * operator new( size_t ); static void operator delete( void * ); obiekty( string dane = "Brak danych" ) : przedstawienie( dane ) , ktory_jestem( ktory_statyczny ) { } static void wyzeruj_zarezerwowane(); friend ostream & operator <<( ostream &, obiekty & ); obiekty * ktory_jestes(); };
char * obiekty::tablica[ 100 ]; int obiekty::wywolan = 0; bool obiekty::zarezerwowane[ 100 ]; int obiekty::ktory_statyczny = 0;
void obiekty::wyzeruj_zarezerwowane() { for( int i = 0; i < 100; i++ ) zarezerwowane[ i ] = false; }
obiekty * obiekty::ktory_jestes() { cout << this->ktory_jestem; ktory_statyczny = this->ktory_jestem; return this; }
void * obiekty::operator new( size_t rozmiar ) { if( wywolan == 0 ) for( int i = 0; i < 100; i++ ) tablica[ i ] = new char[ sizeof( obiekty ) ]; if( wywolan < 100 ) { zarezerwowane[ wywolan ] = true; ktory_statyczny = wywolan; return & tablica[ wywolan++ ]; } else if( wywolan >= 100 ) { int i; for( i = 0; i < 100; i++ ) { if( zarezerwowane[ i ] == false ) break; else if( i == 99 ) { cout << "Nie ma wiecej miejsca!!!" << endl; return 0; } } ktory_statyczny = i; return & tablica[ i ]; } }
void obiekty::operator delete( void * roboczy ) { delete roboczy; zarezerwowane[ ktory_statyczny ] = false; }
ostream & operator <<( ostream & ekran, obiekty & roboczy ) { ekran << "Nazywasz sie: " << roboczy.przedstawienie << endl; return ekran; }
int main() { obiekty::wyzeruj_zarezerwowane(); obiekty * obiekt0 = new obiekty( "Dsa dsa" ); cout << obiekt0->ktory_jestem; obiekty * obiekt1 = new obiekty( "Asd asd" ); obiekty * obiekt2 = new obiekty; cout << obiekt0->ktory_jestem; }
|
|
Monika90 |
» 2016-03-04 19:25:26
return & tablica[ wywolan++ ]; return & tablica[ i ];
|
Zwracasz adres komórki tablicy, a powinieneś zwracać jej zawartość. Ogólnie cały ten program jest jednym wielkim błędem. |
|
Gage Temat założony przez niniejszego użytkownika |
» 2016-03-04 19:37:51 Trochę poprawiłem i wyszło mi coś takiego: Wydaje mi się, że nie działa mi w tym momencie tylko "return 0". Tzn. działa, ale nie tak, jak powinno, bo powoduje zakończenie programu błędem. W nowej wersji ten program to też jeden wielki błąd? Jeśli tak - gdzie go popełniłem? #include <iostream> using namespace std;
class obiekty { static int wywolan; string przedstawienie; static char * tablica[ 100 ]; public: static bool zarezerwowane[ 100 ]; int ktory_jestem; static void * operator new( size_t ); static void operator delete( void * ); obiekty( string dane = "Brak danych" ) : przedstawienie( dane ) { } static void wyzeruj_zarezerwowane(); friend ostream & operator <<( ostream &, obiekty & ); };
char * obiekty::tablica[ 100 ]; int obiekty::wywolan = 0; bool obiekty::zarezerwowane[ 100 ];
void obiekty::wyzeruj_zarezerwowane() { for( int i = 0; i < 100; i++ ) zarezerwowane[ i ] = false; }
void * obiekty::operator new( size_t rozmiar ) { if( wywolan == 0 ) for( int i = 0; i < 100; i++ ) tablica[ i ] = new char[ sizeof( obiekty ) ]; if( wywolan < 100 ) { zarezerwowane[ wywolan ] = true; return & tablica[ wywolan++ ]; } else if( wywolan >= 100 ) { int i; for( i = 0; i < 100; i++ ) { if( zarezerwowane[ i ] == false ) break; else if( i == 99 ) { cout << "Nie ma wiecej miejsca!!!" << endl; return NULL; } } zarezerwowane[ i ] = true; return & tablica[ i ]; } }
void obiekty::operator delete( void * roboczy ) { for( int i = 0; i < 100; i++ ) if( roboczy == & tablica[ i ] ) { delete roboczy; zarezerwowane[ i ] = false; } }
ostream & operator <<( ostream & ekran, obiekty & roboczy ) { ekran << "Nazywasz sie: " << roboczy.przedstawienie << endl; return ekran; }
int main() { obiekty::wyzeruj_zarezerwowane(); obiekty * obiekt0 = new obiekty( "Dsa dsa" ); obiekty * obiekt1 = new obiekty( "Asd asd" ); obiekty * obiekt2 = new obiekty; obiekty * obiekt3 = new obiekty( "Nie wiadomo" ); delete obiekt0; obiekty * obiekt[ 100 ]; for( int i = 0; i < 97; i++ ) obiekt[ i ] = new obiekty; obiekty * obiekt66 = new obiekty; }
|
|
mateczek |
» 2016-03-04 20:09:29 Czytałem symfonie już dawno temu (bardzo mi się podobała jako książka do podstaw) ale takich kwiatków nie pamiętam:P Dla mnie za wielki mix by się połapać o co chodzi. |
|
Gage Temat założony przez niniejszego użytkownika |
» 2016-03-04 20:15:32 Macie rację, mój błąd. Przytaczam treść zadania:
Napisz definicję klasy, a w niej definicję przeładowanego operatora new, który przy tworzeniu pierwszego obiektu tej klasy od razu zarezerwuje pamięć na 100 takich obiektów. Potem, przy każdym następnym użyciu operatora new, będzie on po prostu przydzielał fragment z tego zapasu, który zrobił. Obiekty mogą być tworzone i likwidowane, a operator powinien umieć tą pamięcią gospodarować. W przypadku likwidacji ostatniego obiektu tej klasy, operator delete zwolni tę "100 obiektową" rezerwację.
Czy druga wersja w świetle treści programu jest "jednym wielkim błędem"? Pytam, ponieważ ja prawdę mówiąc tak tego nie widzę, a chciałbym się doskonalić. Dlaczego "return 0" powoduje błąd kończący program? |
|
Monika90 |
» 2016-03-04 20:42:30 Nie poprawiłeś najważniejszej rzeczy return & tablica[ wywolan++ ]; return & tablica[ i ];
to jest źle, powino być return tablica[ wywolan++ ]; return tablica[ i ];
Nie widzę w twoim programie return 0;, jeżeli chodzi Ci o return NULL, to operator new nie może zwracać NULL. |
|
Gage Temat założony przez niniejszego użytkownika |
» 2016-03-04 21:44:03 Absolutna racja, nie wiem dlaczego zwracałem adres do wskaźnika :) Chyba jakaś chwila otępienia, a potem tego nie widziałem. Początkujący chyba tak mają
Wcześniej było tam return 0, z tego co czytałem "0" i "NULL" to przy wskaźniku to samo. Coś źle zrozumiałem? |
|
Monika90 |
» 2016-03-04 22:22:19 We współczesnym C++ nie używa się już 0 ani NULL, teraz ich rolę pełni nullptr.
Ale to szczegół, tutaj chodzi o to, że operator new niepowodzenie powinien sygnalizować rzucając wyjątek std::bad_alloc (lub pochodny), a nie zwracając nullptr.
Ewentualnie można zadeklarować operator new z atrybutem noexcept, wtedy mógłbyś zwracać nullptr. Tylko po co...
I jeszcze jedno, jeżeli dobrze rozumiem co chcesz zrobić, to raczej nie powinieneś zwalniać pamięci w operatorze delete, lecz tylko oznaczyć ją jako nieużywaną. (A delete na wskaźniku typu void* to i tak jest niezdefiniowane zachowanie.) |
|
« 1 » 2 |