Wskażniki i dynamiczna alokacja pamięci.
Ostatnio zmodyfikowano 2016-12-28 19:28
Gajsu Temat założony przez niniejszego użytkownika |
Wskażniki i dynamiczna alokacja pamięci. » 2016-12-28 18:32:39 Witam, jestem na forum nowy. Do założenia konta zachęciła mnie chęć rozwiązania problemu używania wskaźników. C++ uczę się sam z wykorzystaniem internetu i e-bookow. W jednym z filmików na YT odnośnie wskaźników jako przykład zastosowania było skrócenie czasu obliczeń wykonywanych na sporych tablicach, gdyż komputer nie musi sprawdzać sam adresu w spisie treści magistrali adresowej. Jako przykład takiego programu był podany program obliczający czas działania pętli, w której program odczytywał wartość zmiennej z tabeli, a następnie zapisywał wartość w każdej z elementów tabeli. Stworzone zostały dwie takie pętle. Jedna wykorzystywała wskaźniki do wykonania odczytu i zapisu, a druga nie. Logiczne jest więc że czas obliczeń dla pętli bez wskaźników powinien być dłuższy, a pętli wykorzystującej wskaźniki krótszy. Po skompilowaniu i uruchomieniu ku mojemu zdziwieniu występuje zależność odwrotna ! Pętla ze wskaźnikami wykonuje się dłużej. Mam nadzieję że uzyskam tutaj odpowiedź na nutrujące mnie pytanie: Dlaczego tak jest?. Pobrałem również kod udostępniony przez autora filmiku (Myślałem, że może ja gdzieś się pomyliem). Ale działa on tak samo. I jeszcze małe pytanko Gdy zrobię dynamiczną alokację pamięci np. int *jakas_tablica = new int [ile_szufladek];, to po usunięciu tej tablicy delete [] jakas_tablica, wskaźnik zostaje? Bo z tego co rozumiem to można później znowu zarezerwować pamięć posługując się już tylko poleceniem jakas_tablica = new int [ile_szufladek];. Co w takim razie wskazuje wskaźnik *jakas_tablica po usunięciu tablicy? Pierwsze niezajęte miejsce w pamięci ? Pozdrawiam Wszystkich :) Kod umieszczam poniżej: #include <iostream> #include <time.h> #include <cstdlib>
using namespace std;
int ile; clock_t start, stop; double czas;
int main() { cout << "Ile liczb w tablicy: "; cin >> ile; int * tablica = new int[ ile ]; start = clock(); for( int i = 0; i < ile; i++ ) { tablica[ i ] = i; tablica[ i ] += 50; } stop = clock(); czas =( double )( stop - start ) / CLOCKS_PER_SEC; cout << "Czas zapisu (bez wskaznika): " << czas << " s" << endl; delete[] tablica; tablica = new int[ ile ]; int * wskaznik = tablica; start = clock(); for( int i = 0; i < ile; i++ ) { * wskaznik = i; * wskaznik += 50; wskaznik++; } stop = clock(); czas =( double )( stop - start ) / CLOCKS_PER_SEC; cout << "Czas zapisu (ze wskaznikiem): " << czas << " s"; delete[] tablica; return 0; }
|
|
Monika90 |
» 2016-12-28 19:00:12 W jednym z filmików na YT odnośnie wskaźników jako przykład zastosowania było skrócenie czasu obliczeń wykonywanych na sporych tablicach, gdyż komputer nie musi sprawdzać sam adresu w spisie treści magistrali adresowej.
|
To nonsens. Kompilator wygeneruje taki sam kod maszynowy w obydwu przypadkach, (czyli będą jednakowo szybkie), tylko musisz włączyć optymalizacje. |
|
Gajsu Temat założony przez niniejszego użytkownika |
» 2016-12-28 19:11:43 Może źle to sformułowałem. Chodziło mi o to że to przyspieszy nie same obliczenia a po prostu odczyt i zapis do poszczególnych komórek tych tablic. Więc pośrednio obliczenia. Mowa tutaj o filmiku https://www.youtube.com/watch?v=0DQl74alJzwę. Pozdrawiam :) |
|
Monika90 |
» 2016-12-28 19:28:36 Wiem o co chodzi, kurs Zelenta znam od dawna. To co on mówi jest nieprawdziwe, wskaźniki niczego nie przyspieszą, a uzasadnienie "komputer nie musi sprawdzać sam adresu w spisie treści magistrali adresowej" jest nonsensowne. Można to sprawdzić, skompilować taki kod (który jest odpowiednikiem kodu Zelenta, ale lepiej napisanym) #include <ctime> #include <memory> #include <iostream>
template < class Func > void time( Func f ) { auto t1 = std::clock(); f(); auto t2 = std::clock(); std::cout << double( t2 - t1 ) / CLOCKS_PER_SEC << '\n'; }
int main() { const int size = 20 '000' 000; auto a = std::make_unique < int[] >( size ); time([ & ] { for( int i = 0; i < size; ++i ) { a[ i ] = i; a[ i ] += 50; } } ); auto p = a.get(); time([ & ] { for( int i = 0; i < size; ++i ) { * p = i; * p += 50; ++p; } } ); }
i zobaczyć co zrobił kompilator. Tak wygląda pierwsza pętla movl %eax, %esi movl $50, %eax .p2align 4,,10 L4: movl %eax, -200(%ebx,%eax,4) addl $1, %eax cmpl $20000050, %eax jne L4
A tak druga movl %eax, %esi movl $50, %eax .p2align 4,,10 L5: movl %eax, -200(%ebx,%eax,4) addl $1, %eax cmpl $20000050, %eax jne L5
Nie trzeba znać asemblera żeby zauważyć że nie ma różnicy. To był kompilator GCC w wersji 5.2.0 z flagą -O2 |
|
« 1 » |