One of std::string ctor

std::string from C style string ctor

In writing a function template having to create a std::string from a char[], I have had to use the following constructor of std::string:

basic_string( CharT const* s, size_type count, Allocator const& alloc = Allocator() );

which you can find documentation for in the standard or on cppreference.com. In using this constructor, I have had a "off by one" problem with the count parameter. The function template I originally wrote used the constructor like this:

template< std::size_t N >
std::string foo( char const ( &char_arr )[N] ) {
   return std::string( char_arr, N );  // WRONG, do not do this
}

which is a mistake. The terminating '\0' character will be included in the value of N and will thus be part of the std::string (which can contain nulls). Thus, the size of the new std::string will be one more then expected:

char const arr[] = "string";
auto bar = foo( arr );
assert( bar.length() != 6 );
assert( bar.length() == 7 );

Usually, when one is certain that the C style string is null terminated, the recommended way to use the constructor is:

std::string the_strg( char_arr, std::strlen( char_arr ) );

Since std::strlen will not include the null terminator in the length returned. To mimic this behavior, my template had to be written as:

template< std::size_t N >
std::string foo( char const ( &char_arr )[N] ) {
   return std::string( char_arr, N - 1 );
}

which will eliminate the need to calculate the length at runtime and yield the correct std::string with the expected length. This is not exactly a hard problem, but it bit me and I want to remember this little detail!


Edit (2018-09-19): Patrice Roy pointed out that my return statement in the first function was awkward (copy pasting and modifying to make an example is not ideal) and the second version was not returning anything. Fixed now. Thanks Patrice for pointing it out.