2016-06-22 8 views
9

Rozważmy następujący kod:Czy powiązanie odniesienia faktycznie ocenia operand?

int& x=*new int; 

Does RHS przypisania faktycznie dereference nowopowstałej wskaźnika, co prowadzi do UB z powodu czytania zmiennej niezainicjowanej? Czy można to słusznie wykorzystać do późniejszego przypisania wartości takiej jak x=5;?

+2

To jest poprawny kod i jest bezpieczny, dopóki inicjalizujesz 'x' później z pewną wartością, zamiast używać niezainicjowanej zmiennej do jakiegoś celu. Lepszą rzeczą byłoby 'int & x = * new int()', która również inicjuje ją do wartości zerowej. I oczywiście musisz usunąć przydzieloną pamięć. – Arunmu

+4

Nie sądzę, żeby to było coś innego niż 'int y; int & x = y; ', co dzieje się po drodze, gdy robisz' int y; std :: cin >> y; ' – dyp

Odpowiedz

6

O ile wiem, żadne z twoich działań nie dotyczy niezdefiniowanego zachowania.

Powoduje to jednak natychmiastowe ryzyko wycieku pamięci. Może być szybko rozwiązany (ponieważ &x rozwiąże adres adresu wyciekanej pamięci, a zatem może zostać usunięty), ale jeśli opuścisz zakres, nie będziesz w stanie uzyskać tego wskaźnika.

Edycja: do rzeczy, jeśli były, aby napisać

int& x=*new int; 
x = 5; 

std::cout << x << std::endl; 

std::cin >> x; 

std::cout << x << std::endl; 

kod będzie zachowywać się tak, jakby po prostu oświadczył x jako int x;, oprócz tego, że wskaźnik będzie również pozostawić zwisające po program zakończył zakresu .

Osiągniesz niezdefiniowane zachowanie, jeśli spróbujesz odczytać niezainicjowaną zmienną przed przypisaniem jej wartości, ale nie byłoby to nieprawdą, gdyby x było przydzielone w stosie.

+1

@BenjaminLindley Zmieniono język mówiący" stwórz * ryzyko * wycieku pamięci ". Powodem dla którego nazywam to przeciekiem pamięci w pierwszej kolejności jest to, że sam kod nie zawiera widocznego dla użytkownika wskaźnika do pamięci. – Xirema

0

Nie radziłbym tego robić. Aliasing dynamicznej pamięci ze zmienną, która wygląda statycznie, wydaje mi się niebezpieczny. Rozważmy następujący kod

#include <iostream> 

int* dynamicAlloc() { 
    int& x = *new int; 
    std::cout << "Inside dynamicAlloc: " << x << std::endl; 
    std::cout << "Modified: " << (x = 1) << std::endl; 
    return &x; 
} 

int main() { 
    int *dall = dynamicAlloc();; 

    std::cout << "dall (address): " << dall << std::endl; 
    std::cout << "dall -> " << *dall << std::endl; // Memory not cleaned 

    delete dall; // Don't forget to delete 

    return 0; 
} 

mam wyjścia tak:

Inside dynamicAlloc: -842150451 
Modified: 1 
dall (address): 00F642A0 
dall -> 1 

Uwaga jak dereferencing dall nie spowodować segfault. Nie został zwolniony, gdy x wypadł z zakresu. W przeciwnym razie najprawdopodobniej wystąpiłby błąd segfault.

Podsumowując:

int& x sprawia x aliasem dla dynamicznie przydzielonej pamięci. Możesz legalnie modyfikować tę pamięć, ale nie będzie ona czyścić, ponieważ automatycznie wykracza poza zakres, co może prowadzić do potencjalnych wycieków pamięci.

+0

Nie rozumiem tego. Oczywiście nie można użyć wskaźnika po jego usunięciu. Jedynym ryzykiem dla PO jest to, że pamięć nie jest właściwie obsługiwana, może przeciekać. – NathanOliver

+0

Głównym celem było zademonstrowanie, że adres nie jest de-alokowany po tym, jak 'x' wykracza poza zakres w' test() '. Później możesz usunąć 'x', jeśli poprawnie zarządzasz rzeczami, ale nie jest to intuicyjne. Zastanowię się, jak zmienić słowo po tym, jak nie pracuję. – Assimilater

+0

Mam nadzieję, że treść jest teraz nieco lepsza – Assimilater

Powiązane problemy