Watch for dangling std::string_view

Question | Oct 19, 2019 | nwheeler 

A std::string_view object provides a read-only std::string form of interface to a contiguous sequence or array of chars. Typically, a std::string_view object contains a pointer to constant char and a size members. The pointer points to the beginning of the array, and the size has its length.

Here are some elementary examples of std::string_view:

void f(std::string_view sv) {
 std::cout << sv << "\n";
}

std::string s;

// std::string to std::string_view
f(s); 

//literal to std::string_view
f("Hello"); 

// std::string_view::substr returns a std::string_view
f(std::string_view("Hello World").substr(0,5)); 

As std::string_view merely refers to a char sequence, we must ensure that the sequence or array should at least live for the lifetime of the std::string_view. A std::string_view that outlives its array is akin to a dangling pointer, which must be avoided.

Most of the bugs associated with dangling std::string_view arise because a std::string_view inadvertently refers to a char sequence in a temporary std::string object, and we need to be watchful for those typical patterns. Here is an example of dangling std:string_view:

//Returning string_view to a temporary std::string 
// that gets destroyed. 

std::string_view g(const std::string& s) {
  //Bad! substr returned std::string is destroyed
  return s.substr(0,4); 
}

The next example highlights that unlike a const std::string&, a std::string_view does not extend the life of a temporary std::string:

//void f(std::string_view sv);

using namespace std::string_literals; //For literal 's'

//Following is fine because the temporary 
// std::string("Hello") lives until f() returns.
f("Hello"s); //OK 

//But following is bad!
std::string_view v = "Hello"s; 
//Temporary std::string("Hello") is already destroyed here! 
f(v); //Bad! 

Below are some use cases of std::string_view. You have to identify which of these would result in a dangling std::string_view object:

A

std::string_view foo(const std::vector<std::string>& v) {
  // v.front() returns const std::string&
  return v.size() ? v.front() : "";  
}

B

std::string s("Hello");
std::string_view sv = s + " World";    

C

std::string g(){ 
 return "Hello World"; 
}

auto s = g();
std::string_view sv = s;

D

std::string s("Hello World");
std::string_view sv = s.substr(6,5);

Select below all the cases from above which have dangling std::string_view. Note that the correct choices are those which have a dangling std::string_view condition. (Check the Explanations for details)