2010-02-22 17 views
6

Załóżmy, że mam klasę o nazwie A:Jaka jest różnica między tymi dwoma metodami tworzenia obiektów?

Class A 
{ 
... 
} 

A jaka jest różnica między następującymi 2 podejść do instanciate obiektu:

void main(void) 
{ 
    A a; // 1 
    A *pa=new A(); // 2 
} 

W mojej obecnej wiedzy (nie wiem na ten temat jeszcze):

  • sposób 1 przydziela obiektowi na ramie stosu głównej metody(), a więc przedmiot nie usunięta, ponieważ tego deleti on nie ma sensu (nie wiem dlaczego, czy ktoś mógłby to wyjaśnić?).

  • Sposób 2 przydzielić obiektowi w stercie procesu, a także A * vairable PA na ramie stosu głównej metody() tak, obiekt może być usunięty, a i pa można przypisać null po usunięciu.

Mam rację? Jeśli moje zrozumienie jest poprawne, czy ktoś może mi powiedzieć, dlaczego nie mogę usunąć obiektu a ze stosu w podejściu 1?

Dziękujemy ...

+4

Proszę zmienić 'void main (void)' na 'int main()'. – avakar

+0

Tak. Zwykle nie chcesz pisać funkcji (void) {}. Jest to zła składnia wielu autorytetów: http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.4 –

Odpowiedz

1

Approach 1 zadeklarowana zmienna i stworzony obiekt. W Podejściu 2 utworzyłeś instancję i wskaźnik.

EDIT: W podejściu 1 obiekt zniknie z zakresu i zostanie automatycznie usunięty. W podejściu 2 wskaźnik zostanie automatycznie usunięty, ale nie wskaże, na co wskazuje. To będzie twoja praca.

+0

Błąd, nie, wywoływany jest domyślny konstruktor. – gregseth

+1

cześć, fastcodejava, dziękuję za odpowiedź. to jest składnia C++, a nie C#. Podejście 1 tworzy instancję obiektu. Bo mogę uzyskać dostęp do jego zmiennych memorialowych. – smwikipedia

+0

@smwikipedia - Zgadzam się, napisałem zbyt szybko. Poprawiono odpowiedź. – fastcodejava

6

Obiekt a ma automatyczny czas przechowywania, dlatego zostanie automatycznie usunięty na końcu zakresu, w którym został zdefiniowany. Nie ma sensu próba usunięcia go ręcznie. Ręczne usuwanie jest wymagane tylko w przypadku obiektów o czasie przechowywania takim jak , który został przydzielony przy użyciu new.

0

pamięć stosu nie jest zarządzana w taki sam sposób, jak pamięć sterty. nie ma sensu usuwać obiektów ze stosu: będą one automatycznie usuwane po zakończeniu zakresu/funkcji.

4
  1. Przedmiotem żyć czas jest ograniczony do zakres zmienna jest zdefiniowana w , po opuszczeniu zakresu obiekt będą czyszczone. W C++ zakres określony jest przez dowolny blok pomiędzy {odpowiadającym}.
  2. Tutaj tylko wskaźnik znajduje się na stosie, a nie na obiekcie, więc gdy opuścisz lunetę, tylko wskaźnik zostanie oczyszczony, obiekt będzie zawsze gdzieś znajdować.

Do części usuwania obiektu, delete nie tylko wywołuje destruktor obiektu, ale także zwalnia jego pamięć, to nie działałoby, ponieważ zarządzanie pamięcią stosu jest zautomatyzowane przez kompilator, w przeciwieństwie do sterty nie jest zautomatyzowany i wymaga wywoływania nowych i usuwania w celu zarządzania czasem na żywo obiektu.
Każdy obiekt utworzony przez wywołanie nowego musi zostać usunięty jeden raz, ponieważ zapomnienie o tym spowoduje wyciek pamięci, ponieważ pamięć obiektów nigdy nie zostanie zwolniona.

1

Alokacja robi dwie rzeczy:
1) Przydziela pamięć dla obiektu
2) wywołuje konstruktor w przydzielonej pamięci

Usunięcie robi dwie rzeczy:
1) wywołuje destruktor na obiekcie
2) Zwolnienie pamięci używanej przez zniszczony obiekt Po przydzieleniu na stos (A a;), mówisz kompilatorowi "proszę zrobić dla mnie obiekt, poprzez przydzielenie pamięci, a następnie wywołanie t on konstruktor w tej pamięci. A skoro już przy tym jesteś, czy możesz obsłużyć wywoływanie destruktora i zwalnianie pamięci, kiedy wykracza ona poza zakres? Dzięki! "Gdy funkcja (główna) się kończy, obiekt wychodzi poza zasięg, wywoływany jest destruktor, a pamięć zostaje zwolniona. "proszę, uczyń dla mnie przedmiot. Wiem, co robię, więc nie zawracaj sobie głowy wywoływaniem destruktora lub zwalnianiem pamięci. Powiem ci, kiedy to zrobić, innym razem. "Gdy funkcja (główna) się kończy, przydzielony obiekt pozostaje w zakresie i nie jest niszczony ani zwalniany. Mam nadzieję, że masz wskaźnik do niego przechowywany gdzieś indziej w twoim program (jak w, skopiowałeś pa do jakiejś innej zmiennej o większym zasięgu).) Będziesz musiał powiedzieć kompilatorowi, aby zniszczył obiekt i zwolnił pamięć w pewnym momencie w przyszłości, w przeciwnym razie dostaniesz wycieku pamięci.

Po prostu, polecenie "usuń" dotyczy tylko obiektów przydzielonych do sterty, ponieważ jest to ręczny interfejs zarządzania pamięcią w C++ - nowy/usuń.Jest to polecenie dla alokatora sterty, a alokator sterty nie robi " t cokolwiek wiedzieć o obiektach przydzielonych do stosu Jeśli spróbujesz wywołać delete na obiekcie przydzielonym do stosu, możesz równie dobrze wywołać go na losowym adresie pamięci - są to te same rzeczy, o ile alokator sterty jest ustawiony cerned. Bardzo dużo jak próbuje uzyskać dostęp do obiektu poza granice tablicy:

int a[10]; 
std::cout << a[37] << "\n"; // a[37] points at... ? no one knows! 

To po prostu nie ma na to zrobić :)

Edit: PS: Wycieki pamięci są ważniejsze, gdy przydzielasz pamięć w funkcji innej niż main. Kiedy program się kończy, przeciekła pamięć zostaje zwolniona, więc wyciek pamięci w magistrali może nie być wielkim problemem, w zależności od twojego scenariusza. Jednak destruktory nigdy nie są wywoływane na wyciekach obiektów. Jeśli destruktor zrobi coś ważnego, na przykład zamknięcie bazy danych lub pliku, może pojawić się poważniejszy błąd na twoich rękach.

+0

Z technicznego punktu widzenia obiekt nie istnieje przed ukończeniem konstruktora. Konstruktor usuwa obiekt z pamięci pierwotnej. Jeśli konstruktor zgłasza wyjątek, nigdy nie było obiektu. – fredoverflow

+0

Tak, zgadza się. Ja ammend moja odpowiedź –

1

Wyobraź sobie stos jako void* stack = malloc(1.000.000);
Ten blok pamięci jest zarządzany wewnętrznie przez kompilator i procesor.
To jest wspólna pamięć. Każda funkcja może go używać do przechowywania tam tymczasowych obiektów.

To się nazywa automatyczne przechowywanie.Nie można usunąć części tej pamięci, ponieważ jej celem jest ponowne użycie. Jeśli jawnie usuniesz pamięć, ta pamięć wróci do systemu, a nie chcesz, aby to miało miejsce we współużytkowanej pamięci.

W pewnym sensie obiekty automatyczne otrzymują także usunięte. Gdy obiekt znajdzie się poza zakresem, kompilator umieszcza niewidoczne wywołanie obiektu destruktora i pamięć jest ponownie dostępna.

+0

Dzięki Nick. Tak więc stos jest "planowany" w czasie kompilacji i pozostaje zajęty przez program przez całe jego życie, podczas gdy stertę można zażądać i zwolnić w czasie wykonywania. Jeśli tak, a co jeśli rozmiar stosu nie jest wystarczająco duży? czy jego wielkość może zostać skorygowana w czasie uruchamiania? – smwikipedia

+0

@smwikipedia, w rzeczywistości plus kod działa w * wątku *. Zwykle każdy wątek ma własny stos. Jeśli jawnie utworzysz wątek, możesz ustawić jego rozmiar stosu. W systemie Windows zobacz na przykład http://msdn.microsoft.com/en-us/library/ms682453%28VS.85%29.aspx –

+0

... również kompilatory mają opcję ustawienia domyślnego rozmiaru stosu aplikacji. Ponieważ stos ma ustalony rozmiar, może wystąpić przepełnienie stosu: http://en.wikipedia.org/wiki/Stack_overflow –

1

Nie można usuwać obiektów ze stosu, ponieważ jest on zaimplementowany w pamięci dokładnie w ten sposób - jako stos. Podczas tworzenia obiektów na stosie są one dodawane jeden na drugim. Gdy obiekty opuszczają lunetę, są niszczone od góry, w odwrotnej kolejności, w jakiej zostały utworzone (dodaj do góry stosu i usuń z wierzchu stosu). Próba wywołania delete na czymś w stosie spowoduje złamanie tej kolejności. Ta analogia byłaby jak próba wyciągnięcia papieru ze środka stosu papierów.

Kompilator steruje sposobem tworzenia i usuwania obiektów na stosie. Może to zrobić, ponieważ wie dokładnie, jak duży jest każdy obiekt na stosie. Ponieważ rozmiar stosu jest ustawiony w czasie kompilacji, oznacza to, że przydzielanie pamięci dla rzeczy na stosie jest niezwykle szybkie, znacznie szybsze niż przydzielanie pamięci ze sterty, która jest kontrolowana przez system operacyjny.

Powiązane problemy