2012-05-25 1 views
14

У меня есть метод, объявленный следующим образом:Если я укажу значение по умолчанию для аргумента типа «std :: string &» в C++, может ли это вызвать утечку памяти?

/*! 
\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"); 

Определение метода неинтересна, но здесь это все равно:

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); 
} 

В настоящее время в большинстве использований этого метода, я поставляю только первый аргумент. Valgrind дает мне следующее предупреждение:

==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) 

Примечание: «Блоки возможно потеряны»? Я видел утечки памяти, где Valgrind говорит мне, что «блоки определенно потеряны», но это менее определенное сообщение.

Итак, вопрос возникает, я вызываю утечку памяти, назначая значение по умолчанию std::string &? Если да, то что я делаю неправильно?

ответ

13

Нет технической проблемы, но философское создание временного std::string при каждом вызове не так приятно. Особенно с libstdC++ (который вы используете для использования), поскольку он каждый раз вызывает выделение памяти (отсутствие короткой оптимизации строк).

С find_first_not_of имеет перегрузку, принимая char const*, было бы лучше, чтобы обеспечить два перегруженных вместо:

// 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); 

Это также означает, что при вызове Trim(xx, "abc") вы избежите временный std::string генерируется :)

Конечно, решение overkill заключается в повторном использовании уже написанного кода: Boost String Algorithm имеет множество алгоритмов для манипулирования строками, включая trim.

8

Нет проблем.

Временная строка построена при каждом вызове и автоматически уничтожается в конце инструкции. Пока вы не сохраняете ссылку на него, нет проблем.

4

В общем, только новый/malloc без удаления/освобождения приведет к утечке памяти. В вашем случае нет новых вызовов, поэтому утечка памяти не должна. " \t\n\r" находится в памяти стека и повторно каждый раз, чтобы обрешетка экземпляр для std::string &white_chars

Временная экземпляра создается в стеке и быть освобожден после возвращения функции. утечки памяти тоже нет.

+0

Как вы объясните отчет об утечке памяти valgrind? Он указывает, что это происходит, когда строка использовала 'new' (althout в' string :: substr, но ваш ответ ничего не решает. – Shahbaz

+0

@Shahbaz: неправильная диагностика? Valgrind хорошо известна из-за проблем с сообщениями в STL, в основном я думаю, потому что распределитель STL «кэширует» некоторые блоки памяти для последующего повторного использования. –