Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Dziwne zachowanie programu

Ostatnio zmodyfikowano 2016-03-05 19:19
Autor Wiadomość
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!




C/C++
#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();
}; //class obiekty


/*************************************************************************************************/

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;
   
} //wyzeruj_tablice;


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++ ];
    } //if
   
   
    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;
            } //else if
           
        } //for
        ktory_statyczny = i;
        return & tablica[ i ];
       
    } //else if
   
   
} //operator new


void obiekty::operator delete( void * roboczy )
{
    delete roboczy;
    zarezerwowane[ ktory_statyczny ] = false;
   
} //delete



/*******************************************************************************/

ostream & operator <<( ostream & ekran, obiekty & roboczy )
{
    ekran << "Nazywasz sie: " << roboczy.przedstawienie << endl;
    return ekran;
} //operator<<






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;
   
    /*cout<<*obiekt0<<*obiekt1<<*obiekt3;
   
    obiekty *obiekt[100];
   
      for (int i=0; i<96; i++)
        obiekt[i]=new obiekty;*/
   
   
} //main
P-145550
Monika90
» 2016-03-04 19:25:26

C/C++
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.
P-145553
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?


C/C++
#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 & );
}; //class 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;
   
} //wyzeruj_tablice;





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++ ];
    } //if
   
   
    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;
            } //else if
           
        } //for
        zarezerwowane[ i ] = true;
        return & tablica[ i ];
    } //else if
   
   
} //operator new


void obiekty::operator delete( void * roboczy )
{
    for( int i = 0; i < 100; i++ )
    if( roboczy == & tablica[ i ] )
    {
        delete roboczy;
        zarezerwowane[ i ] = false;
    }
} //delete



/*******************************************************************************/

ostream & operator <<( ostream & ekran, obiekty & roboczy )
{
    ekran << "Nazywasz sie: " << roboczy.przedstawienie << endl;
    return ekran;
} //operator<<






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;
   
} //main[/cpp][/code]
P-145555
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.
P-145559
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?
P-145560
Monika90
» 2016-03-04 20:42:30
Nie poprawiłeś najważniejszej rzeczy
C/C++
return & tablica[ wywolan++ ];
return & tablica[ i ];
to jest źle, powino być
C/C++
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.
P-145561
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?
P-145562
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.)
P-145563
« 1 » 2
  Strona 1 z 2 Następna strona