2013-05-16 6 views
5

Oba wywołania get_string i get_string2 zwracają obiekty wykraczające poza zakres, gdy funkcja zwraca. Czy zwracany obiekt nie powinien być adresem w pamięci, który wykracza poza zakres funkcji po powrocie funkcji? To jest za pomocą Visual Studio 2008. Czy to zawsze działa? Czemu?Wskaźnik C++ do obiektów wykraczających poza zakres funkcji, gdy funkcja zwraca - dlaczego to działa?

#include <iostream> 

enum myID { SMALL, MEDIUM, LARGE }; 

const char* get_string(myID id) { 
    switch(id){ 
     case SMALL: return "small"; 
     case MEDIUM: return "medium"; 
     case LARGE: return "large"; 
     default: return "unknown"; 
    } 
} 

const char* get_string2(myID id) { 
    char* s = 0; 
    switch(id){ 
     case SMALL: s = "small"; return s; 
     case MEDIUM: s = "medium"; return s; 
     case LARGE: s = "large"; return s; 
     default: return "unknown"; 
    } 
} 

int main() { 
    std::cout << get_string(SMALL) << std::endl; 
    std::cout << get_string2(SMALL) << std::endl; 
    return 0; 
} 
+0

możliwy duplikat [zwracania wskaźnika do literału (lub stałej) tablicy znaków (ciąg)?] (Http://stackoverflow.com/questions/4836534/returning-a-pointer-to-a-literal-or -constant-character-array-string) –

Odpowiedz

11

literały łańcuchowe są jedynymi, które są literały lwartościami i mają statyczny czas przechowywania. Zatem zwracanie wskaźnika do pierwszego elementu literału ciągu znaków jest bardzo bezpieczne. Porównać

const char* f1() 
{ 
     return "Hello"; // OK 
} 

const char* f2() 
{ 
     const char s[6] = "Hello"; 
     return s; // Undefined Behavior 
} 


const char* f3() 
{ 
     const char* s = "Hello"; 
     return s; //OK 
} 

Sądząc po komentarzach, to odpowiedź potrzebuje opracowania. OK, patrz, literał łańcuchowy jest przechowywany w pamięci do czasu zakończenia programu. W przypadku 1 zwraca wskaźnik do niego. Wskaźnik obiektu jest żywy, więc jest w porządku. W przypadku 3, przenosisz adres literału na zmienną lokalną s i zwracasz ją przez kopiowanie. Kopia adresu nadal wskazuje prawidłową pamięć, więc wszystko jest w porządku. Jednak w drugim przypadku literał literowy zapisujemy w lokalnej tablicy s, która jest niszczona po wyjściu z funkcji. Zwrócenie adresu zmiennej lokalnej jest niezdefiniowanym zachowaniem.

Ponadto, jeśli to, co uważałem za niezdefiniowane zachowanie były faktycznie niezdefiniowana to nie powinien być zaskoczony, ponieważ albo niezdefiniowane zachowanie może oznaczać

  • nie działa
  • czasem działa
  • zawsze działa
  • robi zabawne niewytłumaczalne rzeczy
  • wszystko

Więc jeśli coś działa, to nie znaczy, że jest OK. W tym przypadku jest, ale nie w ogólnym przypadku.

+0

Ponieważ jest to literał łańcuchowy, nie jest on przechowywany jako zmienna stosu? Jest przechowywany w zmiennej globalnej? Czy masz link do strony ze szczegółami tego? –

+0

Czy mógłby Pan wyjaśnić nieco dalej w przypadku niezdefiniowanego zachowania? Po prostu lubię wiedzieć – mr5

+0

@ mr5: Zobacz moją edycję –

4

Ta pamięć nie wychodzi poza zakres. Są to literały łańcuchowe, istnieją one cały czas podczas działania programu.