2011-08-22 16 views
12

Jestem dość początkujący z ciągami C++, więc poniższy wzór może być trochę nieostry. Sprawdzam kod, który napisałem przed rozpoczęciem testowania integracji z większym systemem. Chciałbym wiedzieć, czy jest to bezpieczne, czy też może być narażone na wyciekanie pamięci?Powoduje zwrócenie obiektu C++ std :: string z wycieków pamięci?

string somefunc(void) { 
    string returnString; 
    returnString.assign("A string"); 
    return returnString; 
} 

void anotherfunc(void) { 
    string myString; 
    myString.assign(somefunc()); 
    // ... 
    return; 
} 

Zrozumienie mam to, że wartość returnString jest przypisana do nowego obiektu myString a następnie obiekt returnString ulega zniszczeniu w ramach rozwiązywania wezwanie do somefunc. W pewnym momencie w przyszłości, gdy myString wykracza poza zakres, jest on również niszczony.

Zazwyczaj przekazywałbym wskaźnik do myString do somefunc() i bezpośrednio przypisany do wartości do myString, ale staram się być trochę bardziej klarowny w moim kodzie (i polegając na stylu funkcji efektu ubocznego mniej).

+0

W pierwszej funkcji prawdopodobnie mógłbyś po prostu "zwrócić ciąg znaków (" Ciąg znaków ");" i mają ten sam rezultat. – luiscubal

+0

@luiscubal Jest to uproszczony przykład ilustrujący problem. – Stephen

+2

@luiscubal nawet 'return" Łańcuch ";' jest w porządku, ponieważ std :: string można skonstruować za pomocą ciągów c. – log0

Odpowiedz

10

Tak, zwracając string ten sposób (pod względem wartości) jest bezpieczna, choć wolałbym, przypisując to w ten sposób:

string myString = somefunc(); 

Jest to łatwiejsze do odczytania, a jest także bardziej efektywny (zapisuje konstrukcję pustego ciągu, który zostałby następnie zastąpiony przez następne połączenie z assign).

std::string zarządza własną pamięcią i ma poprawnie napisany konstruktor kopii i operator przypisania, więc można bezpiecznie używać łańcuchów w ten sposób.

2

Tak, jest (przynajmniej normalnie) bezpieczny. Jednym z najbardziej podstawowym wkładem niemal każdej rozsądnej klasy ciągów jest zdolność do działania jako podstawowa wartość, dla której normalne przypisanie, zwroty itp. "Po prostu działają".

7

Tak wykonując

return returnString 

jesteś powołując się napis na copy constructor. Który wykonuje kopię * z returnString w tymczasowym (aka rvalue), który zajmuje miejsce „somefunc()” w wyrażeniu numerem:

myString.assign(somefunc() /*somefunc()'s return becomes temporary*/); 

To z kolei przeszedł do przypisania i używane przez Przypisanie do wykonywania skopiuj do myString.

W twoim przypadku konstruktor kopii ciągów gwarantuje głęboką kopię i zapewnia brak wycieków pamięci.

* Zauważ, że to może być prawdziwa głęboka kopia, zachowanie konstruktora kopiowania jest zależne od implementacji. Niektóre biblioteki ciągów realizują funkcję kopiowania przy zapisie, która ma pewne wewnętrzne prowadzenie ksiąg, aby zapobiec kopiowaniu, aż do momentu, gdy jest to rzeczywiście potrzebne.

+1

W rzeczywistości wykonanie głębokiej kopii zależy od konkretnej implementacji biblioteki standardowej. GCC używa COW, więc konstruktor kopiowania po prostu implikuje inkrementację licznika. –

+0

@Matthieu dobry punkt Wyjaśniłem moją odpowiedź. Dzięki. –

5

Jesteś całkowicie bezpieczny, ponieważ zwracasz ciąg znaków według wartości, gdzie ciąg będzie "kopiowany", a nie przez odniesienie. Jeśli miałbyś zwrócić std::string &, zrobiłbyś to źle, ponieważ miałbyś wiszące referencje. Niektóre kompilatory, nawet, mogą wykonać optymalizację wartości zwracanej , która nawet nie skopiuje łańcucha po powrocie. Aby uzyskać więcej informacji, patrz this post.

0

Jak już napisałeś ciąg returnString jest tworzony wewnątrz somefunc, a kopia jest zwracana po powrocie funkcji. To jest całkowicie bezpieczne.

Należy podać odniesienie do myString do somefunc (nie używać wskaźnika). To będzie zupełnie jasne:

void somefunc(string& myString) { 
    myString.assign("A string"); 
} 

void anotherfunc(void) { 
    string myString; 
    somefunc(myString); 
    // ... 
    return; 
} 
+1

Powoduje pomijanie optymalizacji wartości zwracanych zwykle wykonywanych przez kompilatory, więc nie jest to poprawa. –

+0

@Bo Persson Nigdy nie mówiłem o poprawie wydajności. – log0

+0

"To czego chcesz to ..." dlaczego tak mówisz? Widzę małą przewagę twojego kodu nad tym, co on robi. –

Powiązane problemy