Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If I specify a default value for an argument of type "std::string &" in C++, could that cause a memory leak?

I have a method declared like so:

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

The definition of the method is uninteresting, but here it is anyway:

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

Now in most usages of this method, I supply just the first argument. Valgrind gives me the following warning

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

Note "blocks are possibly lost"? I've seen memory leaks where Valgrind tells me "blocks are definitely lost", but this is a less certain message.

So the question becomes, am I causing a memory leak by assigning a default value to an std::string &? If so, what am I doing wrong?

like image 959
Boinst Avatar asked May 25 '12 07:05

Boinst


People also ask

What is the default value of std::string?

The particular case of the default default value because a default constructed std::string is an empty string.

What are the rules of default argument in C++?

Default Arguments in C++ A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the calling function doesn't provide a value for the argument. In case any value is passed, the default value is overridden.

Can a function argument have default value?

Any number of arguments in a function can have a default value.

Which are the rules for default arguments?

A default argument is a value in the function declaration automatically assigned by the compiler if the calling function does not pass any value to that argument. The values passed in the default arguments are not constant. These values can be overwritten if the value is passed to the function.


2 Answers

There is no technical issue, but philosophically creating a temporary std::string at each call is not so nice. Especially with libstdc++ (which you appear to use) since it causes a memory allocation each time (lack of Short String Optimization).

Since find_first_not_of has an overload taking a char const*, it would be better to provide two overloads instead:

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

This also means that when calling Trim(xx, "abc") you will avoid the temporary std::string being generated :)

Of course, the overkill solution is to reuse already written code: Boost String Algorithm has many algorithms for string manipulation, including trim.

like image 51
Matthieu M. Avatar answered Sep 20 '22 23:09

Matthieu M.


No problem.

The temporary string is constructed at each call, and automatically destroyed again at the end of the statement. As long as you don't save a (dangling) reference to it, there is no problem.

like image 30
Bo Persson Avatar answered Sep 20 '22 23:09

Bo Persson