2012-11-29 13 views
17

Powiedz, mam następujący kod w programie C++:Co oznacza "nowa (i zmienna) wartość" w C++ czy?

Object a = Object(someParameters); 
new (&a) Object(someOtherParameters); 

Moje założenie jest, że zastępuje zawartość a z Object(someOtherParameters), unikając możliwej operator= zgłoszone do Object. Czy to jest poprawne?

+2

Odkładając na bok istniejące odpowiedzi: składnia w * tytule * twojego pytania nie istnieje! Nie możesz używać tej składni z żadną wartością, możesz po prostu użyć jej w wywołaniu konstruktora - tzn. 'Wartość' musi mieć postać' T (argumenty) '. –

+0

nowe miejsce docelowe zawsze używane w puli pamięci C++ (pula obiektów). jako dodatkową odpowiedź. – Healer

Odpowiedz

21

Nazywa się placement new. Wywołuje konstruktor w określonej pamięci, a nie przydziela nową pamięć. Zauważ, że w tym przypadku musisz jawnie wywołać destruktor obiektu przed zwolnieniem przydzielonej pamięci.

Wyjaśnienie. Załóżmy, że przydzielono pewną ilość pamięci pierwotnej i chcesz skonstruować obiekt w tej pamięci. Nazywasz

new(rawMemory) Object(params); 

Teraz przed uwalniając pamięć

delete [] rawMemory; 

trzeba będzie wezwać derstuctor Object wyraźnie

reinterpret_cast<Object*>(rawMemory)->~Object(); 

W danym przykładzie, jednak potencjalny problem jest że nie zniszczyłeś prawidłowo istniejącego obiektu przed zbudowaniem nowego w jego pamięci.

Bonus: kiedykolwiek zastanawialiście się, jak standardowy std::vector można zrobić bez jego obiektów są zawarte default-constructible? Powodem jest to, że w większości, jeśli nie we wszystkich, implementacjach allocator<T> nie zapisuje się T* p, co wymagałoby domyślnej konstrukcji T w przypadku p = new T[N]. Zamiast tego przechowuje wskaźnik char - pamięć pierwotną i przydziela p = new char[N*sizeof(T)]. Gdy obiekt jest push_back, po prostu wywołuje konstruktora kopiowania z nowym położeniem na odpowiednim adresie w tablicy char.

+0

Ostatnie zdanie jest mylące/błędne: destruktor jest automatycznie wywoływany na końcu zakresu, zanim pamięć obiektu zostanie zwolniona. Ale destruktor dla * wcześniej istniejącego * obiektu musi zostać wywołany przed nadpisaniem go. Dla dodatkowej dobroci, ta odpowiedź powinna również wspomnieć o możliwości przeciążenia operatora - potencjalnie przeciążenie powoduje coś zupełnie innego. –

+2

@KonradRudolph: Nie, nie jest. 'Class * object = new (rawMemory) Class (params);' Nie możesz później wywołać 'delete object;', ponieważ pamięć nie została przydzielona przez normalne 'nowe'. Dlatego musisz wywołać jawnie 'object-> ~ Class()' przed wywołaniem 'delete [] rawMemory'. –

+0

Obiekt w pytaniu OP jest przydzielony do stosu i ma poprawny typ, więc sprzeciw nie ma zastosowania.Nawet dla dynamicznie przydzielanej pamięci, możesz bardzo dobrze wykonać następujące czynności: 'T * x = new T; x-> ~ T(); nowy (x) T(); usuń x; '(zanotuj kolejność wywołania destruktora i umieszczenie nowego!) –

6

Znany jest jako umieszczenie nowego: tworzy nowy Object pod adresem podanym w nawiasach. Nowe miejsce docelowe jest zwykle używane do tworzenia obiektu w pamięci pierwotnej. Zbudowanie nowego obiektu na istniejącym, jak robi ten kod, jest złym pomysłem, ponieważ nie wywołuje destruktora na oryginalnym obiekcie.