2010-06-03 16 views
6

OK na pytanie previous zostało udzielone jednoznacznie, ale dowiedziałem się, że inny problem.C++ nowe i usuń i ciąg i funkcje

Co jeśli zrobię:

char *test(int ran){ 
    char *ret = new char[ran]; 
    // process... 
    return ret; 
} 

a następnie uruchomić go:

for(int i = 0; i < 100000000; i++){ 
    string str = test(rand()%10000000+10000000); 
    // process... 

    // no need to delete str anymore? string destructor does it for me here? 
} 

Więc po konwersji char * do łańcucha, nie muszę się martwić o usunięciem więcej?

Edit: Jak odpowiedział muszę delete[] każdy new[] rozmowę, ale w moim przypadku nie jest możliwe, ponieważ jego wskaźnik zgubił, więc pytanie brzmi: w jaki sposób mogę przekonwertować char na ciąg prawidłowo?

+0

Re: Edytuj ... Albo don 't stracić wskaźnik (jak na moją odpowiedź poniżej) lub (jeszcze lepiej) nie "nowy" wskaźnik, wystarczy użyć 'std :: string' do przechowywania ciąg. Dlaczego chcesz samodzielnie alokować pamięć? – Johnsyweb

Odpowiedz

9

Tu nie konwertowaniachar* do [std::]string, ale kopiowaniechar* do [std::]string.

Zgodnie z ogólną zasadą, na każde new powinno być delete.

W tym przypadku trzeba przechowywać kopię wskaźnika i delete go, gdy skończysz:

char* temp = test(rand()%10000000+10000000); 
string str = temp; 
delete[] temp; 
+0

Więc jak właściwie przekonwertować char na ciąg? – Newbie

+0

Zgaduję, że kiedy powiedziano ci, aby konwertować 'char *' na 'std :: string', oznacza to, że powinieneś ** użyć **' std :: string' zamiast 'char *', a nie * convert * programowo. – Johnsyweb

+0

Czy może być jakiś prostszy sposób na zrobienie tego? jak jakąś funkcję lub coś takiego, więc zajęłoby to tylko jeden wiersz kodu? – Newbie

2

Tak, tak.

Jeśli używasz systemu Linux/Mac OS X, patrzeć na coś takiego valgrind które mogą pomóc w rozwiązywaniu problemów pamięć

Można zmienić funkcję testową, tak że zwraca string zamiast char *, w ten sposób co można delete [] ret w funkcji testu.

ALBO możesz po prostu użyć ciągów również w teście i nie musisz się martwić o nowe/usunąć.

+0

Muszę więc użyć: delete [] str; ? – Newbie

+0

Nie, str jest jego własnym obiektem. W takim przypadku utraciłeś wskaźnik do przydzielonego nowego znaku [], przez co będzie miał wyciek pamięci, ponieważ nie możesz go usunąć. –

3

Wydaje się być pod impresison że przepuszczanie char* w std :: ciąg przenosi własność przydzielonej pamięci. W rzeczywistości po prostu tworzy kopię.

Najprostszym sposobem rozwiązania tego problemu jest użycie std :: string w całej funkcji i zwrócenie go bezpośrednio.

std::string test(int ran){ 
    std::string ret; 
    ret.resize(ran - 1); // If accessing by individual character, or not if using the entire string at once. 
    // process... (omit adding the null terminator) 
    return ret; 
} 
+0

+1, aby pominąć etap pośredni tworzenia znaku *. Mimo to Twój przykładowy kod nie ma nazwy ... –

2

Ty koniecznością wezwanie delete dla każdego new inaczej będzie wyciek pamięci. W przypadku, gdy pokazałeś, że rzucasz wskaźnik, jeśli musisz opuścić funkcję jako zwracającą char*, musisz użyć dwóch linii, aby utworzyć std::string, aby zachować kopię char* do delete.

Lepszym rozwiązaniem byłoby przepisanie funkcji test(), aby bezpośrednio zwrócić wartość std::string.

2

Trzeba zrobić coś takiego:

for(int i = 0; i < 100000000; i++){ 
    int length = rand()%10000000+10000000; 
    char* tmp = test(length); 
    string str(tmp); 
    delete[length] tmp; 
} 

to usunięcie przydzielonego char-tablicę prawidłowo.

Nawiasem mówiąc, powinieneś zawsze wyzerować zakończenie ciągu, jeśli utworzysz go w ten sposób (tj. Wewnątrz funkcji test), w przeciwnym razie niektóre funkcje mogą łatwo zostać "zdezorientowane" i traktować dane za ciągiem jako jego częścią, co w najlepszym wypadku powoduje awarię aplikacji, aw najgorszym przypadku tworzenie cichego przepełnienia bufora prowadzącego do niezdefiniowanego zachowania w późniejszym czasie, co jest ostatecznym koszmarem debugowania ...;)