Pointer na iterator a chybná pamäť

asd

Pointer na iterator a chybná pamäť
« kdy: 08. 12. 2011, 17:55:06 »
Zdravim,

1. pouzitie ukazovatelov
Kód: [Vybrat]
#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int SIZE = 2;

struct foo
{
int n;
};

struct proxy
{
void * object;
};

typedef vector<foo> FooVector;
typedef vector<vector<proxy*>*> Tree;
typedef vector<proxy*> Leaf;

Tree ** tree;

foo getFoo(const proxy * p)
{
foo f = *((foo*)p->object);

return f;
}

void addToTree(int n, int index)
{
if (!tree[index])
tree[index] = new Tree;

foo * f = new foo;
f->n = n;

cout << f->n << endl;

Leaf * lPtr = new Leaf;

proxy * proxyPtr = new proxy;
proxyPtr->object = (void*)f;

lPtr->push_back(proxyPtr);

tree[index]->push_back(lPtr);
}

int main()
{
tree = new Tree*[SIZE];
memset(tree, 0, SIZE * sizeof(Tree*));

addToTree(10, 0);
addToTree(11, 1);
addToTree(12, 0);

for (int i = 0; i < SIZE; i++)
{
if (tree[i])
{
for (Tree::iterator t_it = tree[i]->begin(); t_it != tree[i]->end(); t_it++)
{
for (Leaf::iterator l_it = (*t_it)->begin(); l_it != (*t_it)->end(); l_it++)
{
cout << getFoo(*l_it).n << endl;

delete (foo*)((*l_it)->object);
delete *l_it;
}

delete *t_it;
}
}

delete tree[i];
}

delete [] tree;

return 0;
}

vystup

Kód: [Vybrat]
10
11
12
10
12
11

vystup valgrindu:

Kód: [Vybrat]
$ valgrind ./tree_ptr
==7993== Memcheck, a memory error detector
==7993== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==7993== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==7993== Command: ./tree_ptr
==7993==
10
11
12
10
12
11
==7993==
==7993== HEAP SUMMARY:
==7993==     in use at exit: 0 bytes in 0 blocks
==7993==   total heap usage: 18 allocs, 18 frees, 228 bytes allocated
==7993==
==7993== All heap blocks were freed -- no leaks are possible
==7993==
==7993== For counts of detected and suppressed errors, rerun with: -v
==7993== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)

vsetko funguje presne tak ako ma

2. pouzitie ukazovatelov na iteratory
Kód: [Vybrat]
#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int SIZE = 2;

struct foo
{
int n;
};

struct proxy
{
void * object;
};

typedef vector<foo> FooVector;
typedef vector<vector<proxy*>*> Tree;
typedef vector<proxy*> Leaf;

FooVector fooVector;
Tree ** tree;

foo getFoo(const proxy * p)
{
FooVector::iterator * itPtr = (FooVector::iterator*)p->object;
foo f = *(*itPtr);

return f;
}

void addToTree(int n, int index)
{
if (!tree[index])
tree[index] = new Tree;

foo f;
f.n = n;

fooVector.push_back(f);
FooVector::iterator * itPtr = new FooVector::iterator;
(*itPtr) = fooVector.end();
(*itPtr)--;

cout << (*itPtr)->n << endl;

Leaf * lPtr = new Leaf;

proxy * proxyPtr = new proxy;
proxyPtr->object = (void*)itPtr;

lPtr->push_back(proxyPtr);

tree[index]->push_back(lPtr);
}

int main()
{
tree = new Tree*[SIZE];
memset(tree, 0, SIZE * sizeof(Tree*));

addToTree(10, 0);
addToTree(11, 1);
addToTree(12, 0);

for (int i = 0; i < SIZE; i++)
{
if (tree[i])
{
for (Tree::iterator t_it = tree[i]->begin(); t_it != tree[i]->end(); t_it++)
{
for (Leaf::iterator l_it = (*t_it)->begin(); l_it != (*t_it)->end(); l_it++)
{
cout << getFoo(*l_it).n << endl;

delete (FooVector::iterator*)((*l_it)->object);
delete *l_it;
}

delete *t_it;
}
}

delete tree[i];
}

delete [] tree;

return 0;
}

vystup

Kód: [Vybrat]
10
11
12
21618996
12
0

vystup valgrindu:

Kód: [Vybrat]
$ valgrind ./tree_it
==8006== Memcheck, a memory error detector
==8006== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==8006== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==8006== Command: ./tree_it
==8006==
10
11
12
==8006== Invalid read of size 4
==8006==    at 0x400C97: getFoo(proxy const*) (in /home/gman/tree_it)
==8006==    by 0x400EFD: main (in /home/gman/tree_it)
==8006==  Address 0x594d0f0 is 0 bytes inside a block of size 4 free'd
==8006==    at 0x4C2658C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8006==    by 0x4029FD: __gnu_cxx::new_allocator<foo>::deallocate(foo*, unsigned long) (in /home/gman/tree_it)
==8006==    by 0x402265: std::_Vector_base<foo, std::allocator<foo> >::_M_deallocate(foo*, unsigned long) (in /home/gman/tree_it)
==8006==    by 0x40196C: std::vector<foo, std::allocator<foo> >::_M_insert_aux(__gnu_cxx::__normal_iterator<foo*, std::vector<foo, std::allocator<foo> > >, foo const&) (in /home/gman/tree_it)
==8006==    by 0x4011AD: std::vector<foo, std::allocator<foo> >::push_back(foo const&) (in /home/gman/tree_it)
==8006==    by 0x400D10: addToTree(int, int) (in /home/gman/tree_it)
==8006==    by 0x400E66: main (in /home/gman/tree_it)
==8006==
10
12
11
==8006==
==8006== HEAP SUMMARY:
==8006==     in use at exit: 0 bytes in 0 blocks
==8006==   total heap usage: 21 allocs, 21 frees, 268 bytes allocated
==8006==
==8006== All heap blocks were freed -- no leaks are possible
==8006==
==8006== For counts of detected and suppressed errors, rerun with: -v
==8006== ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 4 from 4)



cize halvny rozdiel medzi 1 a 2 je ten, ze v prvom pripade vo funkcii addToTree alokujem pamat a vytvaram novy objekt typu foo, vytvorim proxy a do object priradim adresu vytvoreneho foo objektu. V druhom pripade mi pribudol vector<foo> fooVector. V addToTree si vytvorim objekt typu foo, vlozim ho do fooVector, alokujem pamat pre FooVector::iterator, priradim do nej iterator na konci fooVector kontajneru. A znova ako v 1 si vytvorim proxy ale tento raz si do object priradim adresu iteratora. Aspon mne pripada zeby vysledok mal byt rovnaky, ale ocividne nie je. Takze by som sa chcel spytat, ako rozchodit druhy zdrojak.

Diky moc za odpovede
« Poslední změna: 09. 12. 2011, 10:55:28 od Petr Krčmář »


Sten

Re:pointer na iterator a chybna pamat
« Odpověď #1 kdy: 08. 12. 2011, 18:40:46 »
Chyba je v tom, že iterátory stejně jako ukazatele se mohou měnit (přestanou být platné), když měníte obsah kontejnerů (vektoru).

Mimochodem proč tam máte tak strašně moc ukazatelů? A proč tam vůbec máte ukazatele na iterátory?

asd

Re:pointer na iterator a chybna pamat
« Odpověď #2 kdy: 08. 12. 2011, 19:22:46 »
Citace
Chyba je v tom, že iterátory stejně jako ukazatele se mohou měnit (přestanou být platné), když měníte obsah kontejnerů (vektoru).

aha...mal som si sam vyskusat ci tie iteratory vobec budu potom fungovat takze chyba na mojej strane, aj tak diky

Citace
Mimochodem proč tam máte tak strašně moc ukazatelů?

(toto je samozrejme len cast programu) ten vector bude obsahovat dost vela poloziek a v tomto pripade zaberal ukazovatel menej pamate ako objekt (pretoze v tom programe pouzivam aj 3-rozmerne pole ktore by zaberalo niekolko nasobne viac pamate keby tam boli objekty ako ked su tam ukazovatele). Ale taktiez pravda ze ukazovatel na iterator tam nepotrebujem. Takze existuje vlastne nejaky sposob aby som sa mohol dostat na nejaku polozku kontajneru, ak jeho velkost meni (zvacsuje)?

Sten

Re:pointer na iterator a chybna pamat
« Odpověď #3 kdy: 08. 12. 2011, 19:41:09 »
(toto je samozrejme len cast programu) ten vector bude obsahovat dost vela poloziek a v tomto pripade zaberal ukazovatel menej pamate ako objekt (pretoze v tom programe pouzivam aj 3-rozmerne pole ktore by zaberalo niekolko nasobne viac pamate keby tam boli objekty ako ked su tam ukazovatele). Ale taktiez pravda ze ukazovatel na iterator tam nepotrebujem. Takze existuje vlastne nejaky sposob aby som sa mohol dostat na nejaku polozku kontajneru, ak jeho velkost meni (zvacsuje)?

Existuje, dávat tam místo objektu jenom pointer, adresa objektu se potom nemění. Anebo vektor naplnit a iterátory vytahat až potom. Anebo před naplňováním provést reserve na počet vkládaných prvků, vektor potom nebude měnit velikost a tedy ani iterátory.

To pointerové šílenství zklidní třeba boost::ptr_vector (kromě toho to má i automatický delete).

asd

Re:pointer na iterator a chybna pamat
« Odpověď #4 kdy: 08. 12. 2011, 20:15:16 »
takze tak...diky moc :)


asd

Re:pointer na iterator a chybna pamat
« Odpověď #5 kdy: 08. 12. 2011, 22:33:43 »
tak nakoniec to idem robit tak ze si tam kdesi dam pocitadlo a namiesto iteratorov budem ukladat indexy pretoze vector ma pretazeny operator[] pomocou ktoreho sa da dostat ku jednotlivym prvkom vectoru..uz som to takto chcel robit aj predtym len mi to z nejakeho dovodu neslo