[ Predrag Damnjanovic @ 26.04.2003. 17:35 ] @
Sve lepo radi, prolazi kroz petlje, izvrsava funkcije, i onda od jednom kod malloc-a tras, iz cista mira: Segmentation fault.

Fazon je sto ne puca ispred, gde ima par if-a, i par poziva funkcija, nego bas kod malloc-a, ni pre ni posle.

Ako negde 'gazim' memoriju rezervisanu za program, zasto ne pukne negde ispred, nego bas kod malloc-a?

Pukne ovde:
data = (T *)malloc (_count * sizeof(T));

data nije alociran, to odmah da otklonim kao mogucnost.

Sta moze da bude ovo?
[ Goran Rakić @ 26.04.2003. 18:35 ] @
A da probaš calloc? Koliko sam skapirao malloc ne prazni samu memoriju, samo je alocira... mada ne bi trebalo da bude problema... Takođe probaj gdb a.out pa run i onda ćeš dobiti gde je pukao (libc6 __init_malloc ili slično).
[ Predrag Damnjanovic @ 26.04.2003. 18:45 ] @
ma nema veze calloc, ne alociram niz, obicnu memoriju za char alociram...
moracu definitivno gdb da pocnem da koristim...
[ Predrag Damnjanovic @ 26.04.2003. 19:27 ] @
Evo:
Program received signal SIGSEGV, Segmentation fault.
0x4017ac4e in malloc_consolidate () from /lib/libc.so.6
(gdb) bt
#0 0x4017ac4e in malloc_consolidate () from /lib/libc.so.6
#1 0x4017a77f in _int_malloc () from /lib/libc.so.6
#2 0x401796b5 in malloc () from /lib/libc.so.6
#3 0x080491c4 in papi::array<char>::alloc(int) ()
#4 0x08049123 in papi::array<char>::copy(char*, int, int, int) ()
#5 0x08048b9c in example2() ()
#6 0x08048ea0 in main ()
#7 0x40119bb4 in __libc_start_main () from /lib/libc.so.6

moze li iz ovoga nesto da se sazna?
sta mu je ovo malloc_consolidate ?

ili mi kazite sta da otkucam u gdb-u, posto slabo znam da radim u njemu?
kako se dobijaju podaci sa registara?
[ filmil @ 26.04.2003. 20:37 ] @
Jedna mogućnost: zeznuo si memoriju mnogo pre, ali je tek funkcija malloc natrčala na to.

Drugo: šta traži malloc u C++ programu?

Treće: probaj da koristiš makro assert (heder assert.h). Dosta je zgodan za hvatanje nehotičnih grešaka i za obeležavanje mesta gde treba obraditi grešku. Vrlo je interesatno uraditi recimo:

Code:

#include <assert.h>

/* negde u kodu */

   assert( pointer != 0 );
   /* radi nesto sa tim pointerom */
   /* ... itd */


pa, ako slučajno pointer bude 0 (==NULL) u trenutku kada naiđe assert() biće ispisano ime modula, ime funkcije i broj linije u kojoj je assert okinuo.

Četvrto: ako već koristiš malloc, onda to radi bez eksplicitnog pretvaranja tipova, tj bez (T*). Dobra je praksa (vidi C FAQ).

Peto: a gde je sors? Ako pošalješ, možda možemo kolektivno da izdebagiramo.

f
[ Predrag Damnjanovic @ 26.04.2003. 20:57 ] @
mislis pregazio sam negde program ?
ne znam, verovatno, ali sors izgleda tako cist da nemam reci... tesko cu ja da nadjem sta zeza ovde...
skapirao sam nesto osnovno u gdm-u, ali od toga mi slaba vajda u ovakvoj situaciji, jer je ovde klasican buffer overflow izgleda...

mada, izgleda kao da uopste nije alocirao objekat, pointer ko zna na sta pokazuje, pa pisem/citam po necemu drugom, na to mi najvise smrdi...

pointer 'data' je clanica klase, i kada njega malloc proba da izmeni, program prsne, verovatno zato sto pointer za objekat pokazuje na ko zna sta...
[ filmil @ 26.04.2003. 21:04 ] @
Mislio sam da greška može da sedi na sasvim drugom delu programa. Tri pravila kodiranja u C-u: Careful, careful, careful.

I šta te sprečava da umesto tog „malociranja“ napišeš:

Code:

data = new T[_count]; 


Teško je išta više reći napamet, bez sorsa.

f
[ Predrag Damnjanovic @ 26.04.2003. 21:05 ] @
imam u konstruktoru :
data = 0;

ispred malloc-a imam
if (data==0) throw 0;

definitivno nije ni do sjebanog pointera na objekat, a nije ni kod alokacije objekta, jer bi prso vec kod konstruktora, kod data=0, a i dole vidi da je data==0, sto znaci da je heap objekta OK.

a sors nije bas mali, ima oko 180 + 160 linija, klasa + primer u kom puca...
[ Predrag Damnjanovic @ 26.04.2003. 21:26 ] @
A malloc koristim zbog realloc, cesto prosirujem memoriju.
[ Goran Rakić @ 26.04.2003. 23:10 ] @
pokušaj da lociraš preko: http://developer.kde.org/~sewardj/ ondnosno http://developer.kde.org/~sewardj/docs-1.9.5/manual.html za dokumenataciju...
[ Predrag Damnjanovic @ 26.04.2003. 23:17 ] @
Evo, prvo sam primer sveo na svega 6 linija, zatim sam iz klase uklonio funkcije koje ne koristim, i dosao do destructora, i bingo.

Ja mislim da je problem ovde, imam sledece u klasi:
Code:

array **pointer;


To predstavlja niz pointera na objekte klase 'array'.

U konstruktoru ide:
Code:

pointer=0;


Taj niz alociram ovako:
Code:

pointer = (array **) malloc ( count * sizeof(array *) );


count je duzina niza.
Dakle, tu smestam pointere na objekte, to je niz pointera!

Posle alociranja uradim
Code:

for (int i=0; i<count; i++) pointer[i]=0;


Tako kasnije znam da li pointer pokazuje na neki objekat, kada je 0 to znaci da ne pokazuje na nista.

E sad, objekte kreiram ovako:
Code:

if (pointer[n]!=0)
  pointer[n] = new array;


Mislim da u sledecem kodu gresim, to je destruktor objekta, i on izgleda ovako:

Code:

for (int i=0; i<count; i++)
  if (pointer[i]!=0) 
    delete pointer[i];

if (pointer!=0)
  free (pointer);


Da li gresim negde kod dealokacije niza pointer-a?

P.S. niz ponekad resize-ujem, pa zato koristim malloc/realloc/free za njega.
Za objekte koristim new i delete, posto njih ne resize-ujem :)
[ Predrag Damnjanovic @ 27.04.2003. 01:02 ] @
nadjoh gresku, na skroz drugom mestu :)
valgrind je cudo, gorane tvoj sam duznik :)

greska je nastala zato sto sam ja prvo imao klasu, a posle sam je pretvorio u template klasu, i ovde se zeznuo:

bilo je:
Code:

        for (int i=old_count*size; i<new_count*size; i++)
            data[i]=0;

'data' je bio tipa char, 1 bajt, dok je _size bio velicina objekta koga smestam, i to je radilo.

Kad sam klasu prebacio u template, prepravio sam ono u:
Code:

        for (int i=old_count*sizeof(T); i<new_count*sizeof(T); i++)
            data[i]=0;

a data je bio tipa T.

Sami nadjite gresku :)

da nije valgrind-a, ko zna kad bih ovo primetio :)
[ filmil @ 27.04.2003. 01:55 ] @

Neko je kanda pregazio malo više memorije nego što treba...

f
[ Goran Rakić @ 27.04.2003. 02:44 ] @
da ti samo znaš kako sam ja danas slučajno nabasao na alat ... (gnomedesktop.org čitanje vesti > čitanje bednog intervjua na linuxjournal-u > čitanje teksta o upotrebi i alociranju memorije > čitanje fusnota >...)
[ Predrag Damnjanovic @ 27.04.2003. 13:40 ] @
ako je T 4 bajta, i ako alocira 5 mesta za taj T objekat, gazio je 12 bajta = (4-1)*4
generalno, gazio je mnogo, pogotovu kad alocira vise (10-1)*4... :)

sad sam pustio valgrind da pregleda jedan drugi (moj) projekat, i nasao sam par mojih nebuloza, ne mnogo opasnih, ali ipak mogu da sruse program u odredjenim situacijama...

program je strava :)
[ filmil @ 27.04.2003. 14:40 ] @

A sad još da te pitam zašto ne koristiš vektore iz STL gde ti se ovakve stvari nikada ne bi rešavale, a povrh toga ne bi morao da se patiš sa promenom veličine?

f


[ Predrag Damnjanovic @ 27.04.2003. 16:34 ] @
zato sto je moj vektor mocniji, mozes da mesas tipove objekata koje smestas...
i plus izazov da napisem :)
[ filmil @ 27.04.2003. 16:48 ] @

Ispravi me ako grešim, ali STL vektori mogu isto to, dokle god su elementi izvedeni iz iste klase. To je posledica polimorfizma. Sve što treba je da imaš roditeljsku klasu prema kojoj specijalizuješ šablon. Elemente kontejnera izvodiš iz dotične roditeljske klase i oni se mogu savršeno dobro smestiti u isti kontejner.

Ako pišeš kontejnersku klasu kao vežbu, onda je to sasvim u redu. Ali ako ti je potrebna da bi je koristio kasnije, vredi razmisliti a) da iskoristiš implementaciju koja je data u STL ili bar b) da koristiš isti interfejs kao što je onaj u STL jer onda sebe rešavaš mnogih problema. Napraviti stvar koja je slična po funkcionalnosti sa STL je ogroman posao i pitanje je da li ga ima smisla raditi, pogotovo kad su funkcionalna rešenja na dohvat ruke.

f

[ Predrag Damnjanovic @ 27.04.2003. 20:15 ] @
epa ovde mozes da trpas bas svasta, od char-a do slozenih objekata :)
kao sto rekoh, izazov je razlog, i sto hocu da se oslanjam na sto manje tudjih lib-ova.
[ Rapaic Rajko @ 28.04.2003. 11:15 ] @
Citat:
filmil:

Ispravi me ako grešim, ali STL vektori mogu isto to, dokle god su elementi izvedeni iz iste klase. To je posledica polimorfizma. Sve što treba je da imaš roditeljsku klasu prema kojoj specijalizuješ šablon. Elemente kontejnera izvodiš iz dotične roditeljske klase i oni se mogu savršeno dobro smestiti u isti kontejner.



Izvini, ali upravo gresis.
Vector, strogo uzevsi, NIJE polimorfni kontejner. Obrazlozenje sledi.
Vector je, kao sto svi znamo, template klasa. Dakle, ako kao argument vector-a stavis tip T, a T je neka klasa, i alociras vector na recimo 10 instanci klase T, zauzeta memorija iznosi upravo 10*sizeof(T). Dodajmo na kraj vectora instancu klase T1 koja je izvedena od klase T, i koja recimo ima (private) 2 pointera vise; drugim recima instanca T1 je veca od instance T za 8 bajtova.
Sta se desava kada pokusamo da na kraj vectora dodamo instancu T1? Vector ce na kraju bloka doalocirati sizeof(T) bajtova, i u to pokusati da strpa sizeof(T1) bajtova. Karambol...ili nesto slicno.
Ali, sasvim druga je prica ako upotrebimo vector sa argumentom T*; tada ce raditi polimorfizam. Medjutim, tada si sveo vector na klasican Delphi kontejner. Vector koji alocira 10*sizeof(T*) ustvari alocira 10*4 = 40 bajtova. A gde je memorija za same objekte? Pa na heap-u, obzirom da se oni kreiraju sa new. U stvari, vector sa T* uopste nece dobro raditi, jer moras sam da kreiras i ubijas objekte; vector samo alocira i oslobadja memoriju za pointere (T*).
Doduse, moguce je da u stl-u vec postoji neka klasa koja ovo resava; ali za vector znam pouzdano da ne funkcionise.
Pozdrav

Rajko
[ filmil @ 28.04.2003. 11:29 ] @

Upravo sam mislio na pamćenje pointera (T*) u kontejnerskoj klasi. A što se tiče održavanja objekata koji se sadrže u vektoru, čini mi se da tu nema previše izbora: programer mora sam da se brine o njima. To je C++ način. Mada nisam nikada koristio druge alokatore umesto podrazumevanih, možda bi oni mogli da se napišu tako da vode računa o objektima, uz isti interfejs?

f

[ Dragi Tata @ 28.04.2003. 19:02 ] @
Citat:
filmil:

A sad još da te pitam zašto ne koristiš vektore iz STL gde ti se ovakve stvari nikada ne bi rešavale, a povrh toga ne bi morao da se patiš sa promenom veličine?

f


To, brate, to!!! Ja bih zakonom zabranio upotrebu "built-in" nizova. A posebno mi se ne sviđaju heterogeni nizovi, jer prosto prizivaju nevolje (pitajte C# i Java programere).

Nego, nešto drugo meni ovde bode oči. Koliko mi se čini, Peca koristi malloc da alocira objekte. To je loše, jako loše. Obavezno koristi new i delete, jer malloc ne konstruiše objekte, nego samo alocira memoriju za njih. Što je još gore, free ne garantuje pozivanje destruktora, za razliku od delete.
[ Predrag Damnjanovic @ 28.04.2003. 20:15 ] @
Tata, mislim da si u pravu, ali delimicno.

Postupak ubacivanja objekta ide ovako:
Code:

array<covek> a;
a(0).inic ();
a(1).inic ();
a(2).inic ();


operator() vraca &covek, i pritom vodi racuna da alocira dovoljno prostora za novi objekat (ako je potrebno) : allocated+sizeof(T);
Jedina mana je sto inic() mora da ti bude konstruktor, a pravi konstruktor mora da poziva inic().
Isto i za destruktor.

Ovo vazi u slucaju da bas hoces objekte da trpas u niz.

Sa pointerima nema problema:
Code:

array<covek *> a;
a(0) = new covek;
a(1) = new covek;
a(2) = new covek;


No, da se vratimo na ovo prvo.
Kako ti mislis da nateram new da kreira objekat tamo gde ja hocu (u nizu, gde je rezervisana memorija) ?
Ja tu tehniku ne poznajem.
Da li to postoji u STL biblioteci?

P.S. Ja pojma nemam sta sve STL klase mogu, ali ovo moja klasa sama kreira podnizove (mozes da imas koliko hoces dimenzija), zatim mozes da obrises niz (u bilo kojoj dimenziji), mozes rucno da alociras memoriju u nekom nizu, mozes da je dealociras, mozes da vidis duzinu niza, mozes da vidis koliko podnizova ima neki niz (u bilo kojoj dimenziji), mozes da ispitas da li odredjeni podniz postoji, mozes da kopiras neku memoriju/string u nekom nizu, i mozes da pristupis bilo kom bajtu, preko funkcije koja vraca void* na trazeni bajt, pa tako mozes da ubacis/procitas sta hoces na bilo kom mestu.
Sve ovo uz automatsku alokaciju.
Ako uradis recimo :
Code:

niz[5][2][8][4][3][9](5) = 55;

zauzeces svega nekih 70 bajta, jer se alociraju samo podnizovi, samo 'putanja', a ne cela objast.
I mozes u jedan podniz da drzis babe, a u drugi podniz zabe, i nema gazenja :)

Evo primera:
Code:

void example1 ()
{
    papi::array<int> a;

    a(0) = 0;
    a(1) = 1;
    a(2) = 2;
    a(3) = 3;
    a(4) = 4;

    a[1](0) = 10;
    a[1](1) = 11;
    a[1](2) = 12;

    a[1][8](5) = 185;
    
    printf ("[0] = %i\n", a(0) );
    printf ("[1] = %i\n", a(1) );
    printf ("[2] = %i\n", a(2) );
    printf ("[3] = %i\n", a(3) );
    printf ("[3] = %i\n", a(4) );

    printf ("[1][0] = %i\n", a[1](0) );
    printf ("[1][1] = %i\n", a[1](1) );
    printf ("[1][2] = %i\n", a[1](2) );

    printf ("[1][8][5] = %i\n", a[1][8](5) );
    
    printf ("array's root have : %i data cells\n", a.length());
    printf ("array's root have : %i sub-arrays\n", a.sa_length());
    printf ("[1] have : %i data cells\n", a[1].length());
    printf ("[1] have : %i sub-arrays\n", a[1].sa_length());
    printf ("[1][8] have : %i data cells\n", a[1][8].length());
    printf ("[1][8] have : %i sub-arrays\n", a[1][8].sa_length());
}

void example2 ()
{
    papi::array<char> a;
    a.copy ("Countries");
    a[0].copy ("Europe");

    a[0][0].copy ("Serbia and Montenegro");
    
    a[0][1].copy ("France");
    a[0][2].copy ("Germany");
    a[0][3].copy ("Englend");
    a[0][4].copy ("Italy");

    a[1].copy ("Asia");
    a[1][0].copy ("Rusia");
    a[1][1].copy ("China");
    a[1][2].copy ("Japan");
    a[1][3].copy ("India");
    a[1][4].copy ("Pakistan");

    a[2].copy ("Africa");
    a[2][0].copy ("Nigeria");
    a[2][1].copy ("Egypt");
    a[2][2].copy ("Tunis");
    a[2][3].copy ("Maroko");
    a[2][4].copy ("Etiopia");

    a[3].copy ("Australia & Oceania");
    a[3][0].copy ("Australia");
    a[3][1].copy ("New Zeland");

    a[4].copy ("North America");
    a[4][0].copy ("Brasil");
    a[4][1].copy ("Argentina");
    a[4][2].copy ("Columbia");

    a[5].copy ("South America");
    a[5][0].copy ("USA");
    a[5][1].copy ("Canada");
    a[5][2].copy ("Cuba");
    a[5][3].copy ("Puerto Rico");

    a[6].copy ("Grenland");
    a[6][0].copy ("Grenland");
    
    printf ("- %s\n", a.p() );
    int i;
    for (int j=0; j<a.sa_length(); j++)
        if (a.sa_exist(j))
        {
            printf ("--- %s\n", a[j].p() );
            for (i=0; i<a[j].sa_length(); i++)
                if (a[j].sa_exist(i))
                    printf ("------ %s\n", a[j][i].p() );
        }
}

void example3 ()
{
    papi::array<char> a;
    
    a[1](0) = 'a';
    a[1](1) = 'b';
    
    *(int *)a[0].vp(0) = 10;
    *(int *)a[0].vp(4) = 14;

    a[1](2) = 'c';
    a[1](3) = 'd';

    printf ("a[0](0) = %i\n", *(int *)a[0].vp(0) );
    printf ("a[0](1) = %i\n", *(int *)a[0].vp(4) );
    printf ("a[1](0) = %c\n", a[1](0) );
    printf ("a[1](1) = %c\n", a[1](1) );
    printf ("a[1](2) = %c\n", a[1](2) );
    printf ("a[1](3) = %c\n", a[1](3) );
}


Zar je toliko lose sto sam napravio ovo? :)
[ Dragi Tata @ 28.04.2003. 20:35 ] @
Peco, ne kažem ja da je loše to što si napravio, već sam rekao da je loše:

1) Koristiti malloc za objekte.
2) Koristiti built-in nizove.

Pogledaj http://www.glenmccl.com/bett_003.htm

"The first is that new and delete in C++ have more than one function. The new operator allocates storage, just like malloc() in C, but it is also responsible for calling the constructor for any class object that is being allocated. For example, if we have a String class, saying:


String* p = new String("xxx");

will allocate space for a String object, and then call the constructor to initialize the String object to the value "xxx". In a similar way, the delete operator arranges for the destructor to be called for an object, and then the space is deallocated in a manner similar to the C function free().


If we have an array of class objects, as in:


String* p = new String[100];

then a constructor must be called for each array slot, since each is a class object. Typically this processing is handled by a C++ internal library function that iterates over the array.


In a similar way, deallocation of an array of class objects can be done by saying:


delete [] p;
"


Citat:
Kako ti mislis da nateram new da kreira objekat tamo gde ja hocu (u nizu, gde je rezervisana memorija) ?


Koristiš "placement new" http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10

[ filmil @ 28.04.2003. 22:10 ] @

Placement new valja uramiti. Više puta.

f
[ Predrag Damnjanovic @ 29.04.2003. 01:29 ] @
Placement new mozes odmah da koristis, ovako:
Code:

array<covek> a;
new (&a(0)) covek("Tata");
a(0).cao();


Ne vidim ni kako bi to moglo drugacije da se implementira.
Ako napravim funkciju koja to radi - kako onda da znam parametre koje trebam konstruktoru da prosledim? :)
Po meni to nije uopste moguce!

Drugo, sta podrazumevas pod built-in nizovima?
Ne znam na sta mislis pod tim pojmom?

[Ovu poruku je menjao Predrag Damnjanovic dana 29.04.2003. u 01:54 GMT]
[ 6544616a006e @ 30.04.2003. 02:21 ] @
Ovo je debelo standardna početnička C++ priča... koja se ukratko završava na: C++ programer si? - Koristiš new/delete. C programer si? - Koristiš malloc/free (ili nešto deseto, ili pišeš sopstvene funkcije za alociranje/dealociranje). Modula3 programer si? - Ne razmišljaš previše. Java programer si? - (Skoro) isto kao sa Modulom.
[ Dragi Tata @ 30.04.2003. 02:39 ] @
Citat:
Predrag Damnjanovic:

Drugo, sta podrazumevas pod built-in nizovima?
Ne znam na sta mislis pod tim pojmom?


Mislim na nizove koji se alociraju sa new ili nedajbože malloc. I najzeleniji C++ početnik treba da nauči da koristi std::vector i std::string.

[ Predrag Damnjanovic @ 30.04.2003. 14:13 ] @
tata, kada objavim klasu shvatices prednosti ove, i shvatices zasto ne koristim vector :)

6544616a006e : vec sam rekao zasto ne koristim new, ali evo opet cu: sa new ne mogu da prosirujem niz, ne postoji renew, kao sto postoji realloc.

Inace, new koristim za kreiranje objekata u nizu:
Code:

    array<man> a;
    new (&a(0)) man("Peca", 83);
    new (&a(1)) man("Mike", 81);
    new (&a(2)) man("Billy", 75);
    printf ("1. man : name : %s \t age : %i\n", a(0).name, a(0).age );
    printf ("2. man : name : %s \t age : %i\n", a(1).name, a(1).age );
    printf ("3. man : name : %s \t age : %i\n", a(2).name, a(2).age );
    a(0).~man();
    a(1).~man();
    a(2).~man();


malloc sluzi samo za rezervisanje memorije.
[ Dragi Tata @ 30.04.2003. 19:01 ] @
Peco, nemoj pogrešno da me shvatiš. Sasvim je OK koristiti klasu kao što je tvoja umesto built-in nizova, pod uslovom da je dobro istestiraš. Kao što rekoh, ja sam protivnik direktnog korišćenja built-in nizova u kodu, a takve wrapper klase su daleko bolje rešenje.
[ Predrag Damnjanovic @ 02.05.2003. 14:41 ] @
Klasu maximalno testiram, i kroz primere (ima ih 7) i kroz moja 2 komercijalna projekta, gde je bas forsiram, i plus proveravam uz pomoc memory check programa, kao sto je valgrind, nema ni memory leak-a, ni prelivanja bafera, niti bilo cega drugog.

Na kraju, ja zaista nemam nameru niti da reklamiram klasu, niti teram nekog da je koristi, za sebe sam je pravio...
Bice unutar moje biblioteke, kao opensource, za par nedelja...
[ leka @ 12.05.2003. 14:52 ] @
Ja se nikad necu navici na std:: iako se to preporucuje svim C++ programerima... Isto vazi i za sablone. Celog zivota cu sam pisati kod koji ili koristi new/delete ili (m|c|re)alloc(a)/free . Jeste da je sa std:: brze (razvoj je brzi), ali sa ovim drugim nacinom mi je kod mnogo kompaktniji i brzi (uvek!). Nazalost, od onih ljudi sam koji bi zrtvovali vreme za malo brzine uvek...