2012-05-25 15 views
14

Mam metody zadeklarowane tak:Jeśli określę wartość domyślną dla argumentu typu "std :: string &" w C++, może to spowodować wyciek pamięci?

/*! 
\brief Removes the leading and trailing white space from a string. 
\param s The string to remove the white space from. 
\param white_chars Characters to be considered as whitespace. 
*/ 
std::string Trim(const std::string &s, const std::string &white_chars = " \t\n\r"); 

Definicja metody jest nieciekawe, ale tutaj jest to w każdym razie:

std::string Trim(const std::string &s, const std::string &white_chars) 
{ 
    size_t startidx = s.find_first_not_of(white_chars); 
    if (startidx == std::string::npos) return ""; 
    size_t endidx = s.find_last_not_of(white_chars); 
    return s.substr(startidx, endidx - startidx + 1); 
} 

Teraz w większości zastosowań tej metody, I dostarczyć tylko pierwszy argument. Valgrind przekazuje mi następujące ostrzeżenie:

==3338== 68 bytes in 2 blocks are possibly lost in loss record 4,639 of 7,212 
==3338== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3338== by 0x728CA88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16) 
==3338== by 0x728E2B4: char* std::string::_S_construct<char*>(char*, char*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16) 
==3338== by 0x728E414: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16) 
==3338== by 0x728E441: std::string::substr(unsigned long, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16) 
==3338== by 0x6965F0A: str::Trim(std::string const&, std::string const&) (appbase.cpp:90) 
==3338== by 0x5F481D7: netopt::Element::set_ID(std::string const&) (netopt_elem.cpp:85) 

Uwaga "bloki prawdopodobnie zaginęły"? Widziałem przecieki pamięci, w których Valgrind mówi mi "bloki są zdecydowanie stracone", ale jest to mniej pewna wiadomość.

Pojawia się zatem pytanie, czy przyczyną wycieku pamięci jest przypisanie wartości domyślnej do wartości std::string &? Jeśli tak, co robię źle?

Odpowiedz

13

Nie ma problemu technicznego, ale filozoficzne tworzenie tymczasowego numeru std::string przy każdym połączeniu nie jest takie przyjemne. Zwłaszcza z libstdC++ (który wydaje się być użyty), ponieważ powoduje przydział pamięci za każdym razem (brak krótkiej optymalizacji ciągu).

Od find_first_not_of ma przeciążenie biorąc char const*, byłoby lepiej, aby zapewnić dwa przeciążeń zamiast:

// First, the one with the default argument, but without a temporary 
std::string Trim(std::string const& s, char const* white_chars = " \t\n\r"); 

// Second, for convenience, one with a `std::string` 
std::string Trim(std::string const& s, std::string const& white_chars); 

Oznacza to również, że podczas wywoływania Trim(xx, "abc") unikniesz tymczasowy std::string generowane :)

Oczywiście rozwiązaniem przesadnym jest ponowne użycie już napisanego kodu: Boost String Algorithm ma wiele algorytmów manipulowania ciągami, w tym trim.

8

Nie ma problemu.

Łańcuch tymczasowy jest tworzony przy każdym połączeniu i automatycznie ponownie niszczony na końcu wyciągu. Tak długo, jak nie zapisujesz odniesienia do niego (zwisającego), nie ma problemu.

4

Ogólnie rzecz biorąc, tylko nowa/malloc bez delete/free spowoduje wyciek pamięci. W twoim przypadku nie ma nowego wywoływanego, więc nie powinno się przeciekać pamięci. Urządzenie " \t\n\r" jest w pamięci stosu i jest ponownie używane za każdym razem, aby utworzyć instancję tymczasową utworzoną w stosie i zwolnioną po powrocie funkcji. nie ma również wycieku pamięci.

+0

Jak zatem wyjaśnisz raport wycieku pamięci valgrind? Wskazuje, że zdarza się, gdy string używał 'new' (alithout w' string :: substr, ale wciąż twoja odpowiedź niczego nie rozwiązuje) – Shahbaz

+0

@Shahbaz: misdiagnosis? Valgrind jest dobrze znany z raportowania problemów w STL, głównie I myślę, ponieważ alokator STL "buforuje" niektóre bloki pamięci do późniejszego wykorzystania. –