• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Dynamiczny przydział pamięci

VPS Starter Arubacloud
0 głosów
560 wizyt
pytanie zadane 7 stycznia 2017 w C i C++ przez Evelek Nałogowiec (28,960 p.)
#include <iostream>
#include <cstdlib>
using namespace std;

class Klasa
{
private:
	int zmienna;
public:
	Klasa(int zmienna_ = 0) : zmienna(zmienna_) {}
	~Klasa() {}
};

int main()
{
	Klasa *wskaznik[3];
	int zmienna1;
	for (int i = 0; i < 2; i++)
	{
		cout << "Podaj liczbe: ";
		cin >> zmienna1;
		wskaznik[i] = new Klasa(zmienna1);
	}
	//usuwamy pierwszy obiekt
	delete wskaznik[0];

	cin >> zmienna1;
	wskaznik[2] = new Klasa(zmienna1);
	//okazuje sie, ze przypisalo sie do wskaznik[0] i wskaznik[2]
	system("pause");
}

Mam pytanie do tego programu. Na początku podajemy pierwszą liczbę, obiekt jest przypisywany do wskaznik[0]. Następnie podajemy kolejną liczbę, obiekt jest przypisywany do wskaznik[1]. Następnie usuwamy obiekt z miejsca wskaznik[0]. Następnie tworzymy nowy obiekt i przypisujemy do wskaznik[2]. Co się okazuje, obiekt ten został przypisany do wskaznik[0] oraz wskaznik[2]. Dlaczego tak się dzieje? Dlaczego nie przypisuje go tylko do wskaznik[2]?

3 odpowiedzi

0 głosów
odpowiedź 7 stycznia 2017 przez Michał Muzyka Pasjonat (24,080 p.)

U mnie wszystko działa bez zastrzeżeń. Dodałem:
 

  //w klasie zmienną zmieniłem na publiczną 

  for (int i = 0; i < 3; i++)
    {
        cout << "z" << wskaznik[i]->zmienna << " ";
    }

i wyświetlają się różne obiekty

komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
A czy to jest odpowiedź na moje pytanie? Ja chciałem się dowiedzieć, dlaczego w tym konkretnym przypadku tak się dzieje.
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
Poza tym nie może ci się wyświetlić wskaznik[0] skoro napisaliśmy delete wskaznik[0]. Powinieneś dostać błąd odczytu pamięci.
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
A jeśli ci się odczytuje to odczytuje to samo co w wskaznik[2].
komentarz 7 stycznia 2017 przez Michał Muzyka Pasjonat (24,080 p.)
może ci się wyświetlić dlatego że wskaźnik wskazuje na to samo miejsce w pamięci, jeśli używasz delete to zwalnia sie przydział pamięci dla tego programu, ale w wskaźnik wskazuje na to samo miejsce, w którym nie została nadpisana twoja zmienna. Nie odczytuje się to co w wskaznik[2], wyświetla to co było wcześniej. wpisz couta do destruktora i zobacz że jest on poprawnie usuwany
komentarz 7 stycznia 2017 przez MichuDev Pasjonat (20,300 p.)
A na marginesie, klasa powinna być zamknięta, nie powinna nikogo obchodzić implementacja. Nie powinno się robić publicznych pól (zmiennych instancji klasy). Jeśli chodzi o jakość kodu, nawet jak coś zadziała nie będzie to profesjonalnie wykonane!
komentarz 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)
Jeśli użyjesz delete na wskaźniku a potem dokonasz na nim dereferncji to program ma UB.
komentarz 7 stycznia 2017 przez Michał Muzyka Pasjonat (24,080 p.)
no dobrze że powinna być zamknięta ale dla ułatwienia testów możemy na razie zmienić pole na publiczne, bo to nie jest gotowa klasa czy biblioteka
komentarz 7 stycznia 2017 przez MichuDev Pasjonat (20,300 p.)
Na chwilę można to zrobić, ale przy refaktoryzacji powinno się to zmienić!
komentarz 7 stycznia 2017 przez Michał Muzyka Pasjonat (24,080 p.)
no i co w związku z tym? Kolega testuje jakieś działanie na klasach więc po co ma ustawiać zmienne na prywatne to troche mija się z celem, jak się coś testuje na szybko powinno się to robić tak by dla nas było łatwiej a nie np do każdej zmiennej pisać settera i gettera to bezsens.
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)

Tak jak Michał napisał - w formie testów. Zrobiłem większy program w którym mi pokazuje błędy i chciałem przenieść tą sytuację do tego małego programiku, aby łatwiej było namierzyć przyczynę problemu.

może ci się wyświetlić dlatego że wskaźnik wskazuje na to samo miejsce w pamięci, jeśli używasz delete to zwalnia sie przydział pamięci dla tego programu, ale w wskaźnik wskazuje na to samo miejsce, w którym nie została nadpisana twoja zmienna. Nie odczytuje się to co w wskaznik[2], wyświetla to co było wcześniej. wpisz couta do destruktora i zobacz że jest on poprawnie usuwany

O właśnie, dzięki Michał, to jest odpowiedź na moje pytanie. Nie do końca to chyba jeszcze rozumiem - delete wskaznik[0] - usuwam obiekt, który był wskazywany przez wskaznik[0]. Następnie chcę przypisać nowy obiekt, ale do wskaznik[2]. Odpalam debugera, podglądam zawartość zmiennych i okazuje się, że po stworzeniu obiektu w wskaznik[2], obiekt się stworzył również w wskaznik[0]. Jak to możliwe? wskaznik[0] oraz wskaznik[2] wskazują to samo miejsce w pamięci? Jeśli tak jest to zapytam o rozwiązanie tego problemu: co zrobić, aby ten obiekt przypisywał się tylko do wskaznik[2] a wskaznik[0] pozostał usunięty?

 

komentarz 7 stycznia 2017 przez Michał Muzyka Pasjonat (24,080 p.)
obiekt jest usunięty może jest to kwestia debbugera, możesz to sprawdzić dodając np. couta w destruktorze i konstruktorze,. Może to być też kwestia kompilatora którego używasz. No właśnie z jakiego korzystasz?
komentarz 7 stycznia 2017 przez morele123 Gaduła (4,790 p.)
Robisz to na tablicy statycznej, więc co najwyżej możesz po usunięciu zawartości wskaznik[0] ustawić go na NULL.
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)

Michał, zerknij na to, skopiuje ten komentarz:

Zmienne po utworzeniu dwóch obiektów i przypisaniu ich do wskaznik[0] oraz wskaznik[1].

Zmienne po usunięciu obiektu: delete wskaznik[0]

Widzimy, że zawartość wskaznik[0] została wyczyszczona i znajduje się tam obecnie syf z pamięci.

Teraz tworzymy obiekt w wskaznik[2]:

Co się okazało? wskaznik[0] oraz wskaznik[2] wskazują ten sam obszar pamięci i obiekt jest przypisywany zarówno do wskaznik[0] i wskaznik[2]. Ja chcę wiedzieć dlaczego tak się dzieje i jak zrobić, aby ten obiekt się nie przypisywał do wskaznik[0].

komentarz 7 stycznia 2017 przez Michał Muzyka Pasjonat (24,080 p.)

Wydaje mi się ze to problem twojego środowiska, bo u mnie:
Visual Studio 15

komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
Visual Studio 2017 RC. Ehh.. co z tym można zrobić?
0 głosów
odpowiedź 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)
Skąd wiesz co jest w wskaznik[0] ?
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
Debuguje i podglądam wartości zmiennych.
1
komentarz 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)
Po użyciu delete na wskaźniku staje się on niepoprawny.
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
Co to znaczy "niepoprawny"? I dlaczego w tym przypadku, gdy chcę stworzyć obiekt i przypisać go do wskaznik[2], to obiekt ten jest tworzony w dwóch miejscach jednocześnie: wskaznik[0] oraz wskaznik[2]?
komentarz 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)

Niepoprawny znaczy, że juz nie wskazuje na zaalakowaną pamięć.

I dlaczego w tym przypadku, gdy chcę stworzyć obiekt i przypisać go do wskaznik[2], to obiekt ten jest tworzony w dwóch miejscach jednocześnie: wskaznik[0] oraz wskaznik[2]?

Nie jest tworzony w dwóch miejscach jednocześnie. Gdy wywołałes delete na wskaźniku to robienie z nim cokolwiek nie ma sensu. 

komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)

Zmienne po utworzeniu dwóch obiektów i przypisaniu ich do wskaznik[0] oraz wskaznik[1].

Zmienne po usunięciu obiektu: delete wskaznik[0]

Widzimy, że zawartość wskaznik[0] została wyczyszczona i znajduje się tam obecnie syf z pamięci.

Teraz tworzymy obiekt w wskaznik[2]:

Co się okazało? wskaznik[0] oraz wskaznik[2] wskazują ten sam obszar pamięci i obiekt jest przypisywany zarówno do wskaznik[0] i wskaznik[2]. Ja chcę wiedzieć dlaczego tak się dzieje i jak zrobić, aby ten obiekt się nie przypisywał do wskaznik[0].

komentarz 7 stycznia 2017 przez Michał Muzyka Pasjonat (24,080 p.)

Wydaje mi się że jest to po prostu problem środowiska. Ja używam Visual Studio 15

komentarz 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)
Nie wiem. Być może bug debuggera, kompilatora(a może jego optymalizacja).
0 głosów
odpowiedź 7 stycznia 2017 przez operator Stary wyjadacz (10,920 p.)
Nie możesz kasować obiektów z tablicy w ten sposób ponieważ nie zmniejszasz rozmiaru tablicy.
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
Tu własnie o to chodzi, aby nie zmniejszać wielkości tablicy.
komentarz 7 stycznia 2017 przez operator Stary wyjadacz (10,920 p.)
Nie da się bo nie. Też kiedyś miałem z tym problem. Czasami słyszę takie odpowiedzi do ćwiczeniowca i zakładam, że ma rację i ma.
komentarz 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)
A po co zmniejszać rozmiar tablicy?
komentarz 7 stycznia 2017 przez operator Stary wyjadacz (10,920 p.)
Jeśli tego nie zrobisz dostaniesz sygnał 6.
komentarz 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)
Nie, nie dostaniesz.
komentarz 7 stycznia 2017 przez operator Stary wyjadacz (10,920 p.)
Racja. Generalnie tak to wygląda w pamięci.

Bez kasowania:

0x90aea10 0x90aea20 0x90aea30

delete wskaznik[0];

0x8539a10 0x8539a20 0x8539a10

delete wskaznik[1];

0x8b6aa10 0x8b6aa20 0x8b6aa20

delete wskaznik[0];
delete wskaznik[1];

0x9c88a10 0x9c88a20 0x9c88a20
komentarz 7 stycznia 2017 przez unknown Nałogowiec (39,560 p.)
Wywoływanie delete 2 razy(lub więcej) na tym samym wskaźniku to UB
komentarz 7 stycznia 2017 przez Evelek Nałogowiec (28,960 p.)
To troszkę lipnie z tą pamięcią...

Podobne pytania

0 głosów
1 odpowiedź 465 wizyt
pytanie zadane 26 czerwca 2017 w HTML i CSS przez sapero Gaduła (4,100 p.)
0 głosów
1 odpowiedź 441 wizyt
pytanie zadane 3 września 2016 w C i C++ przez sofnir Gaduła (4,690 p.)
0 głosów
0 odpowiedzi 410 wizyt
pytanie zadane 11 czerwca 2016 w C i C++ przez L33TT12 Gaduła (3,950 p.)

92,452 zapytań

141,262 odpowiedzi

319,077 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...