48

I have a class:

class Symbol_t {
public:
   Symbol_t( const char* rawName ) {
      memcpy( m_V, rawName, 6 * sizeof( char ) );
   };

   string_view strVw() const {
      return string_view( m_V, 6 );
   };

private:
   char m_V[6];

}; // class Symbol_t

and there is a lib-func that I can't modify:

extern bool loadData( const string& strSymbol );

If there is a local variable:

Symbol_t   symbol( "123456" );

When I need to call loadData, I dare not do it like this:

loadData( string( symbol.strVw().begin(), symbol.strVw().end() ) );

I have to do like this:

string_view svwSym = symbol.strVw();
loadData( string( svw.begin(), svw.end() ) );

My question: Is the first method correct? or I must use the second one?

Because I think that in Method 1, the iterators I passed to the constructor of std::string, are of two Different string_vew objects, and theoretically the result is undefined, even though we would get expected result with almost all of the C++ compilers.

Any hints will be appreciated! thanks.

3 Answers 3

59

There is no need to use the c'tor taking a range. std::string has a constructor that operates in terms of std::string_view, number 16 in the list. The effect of which is

template< class StringViewLike >
explicit basic_string( const StringViewLike& t,
                       const Allocator& alloc = Allocator() ); 

Implicitly converts t to a string view sv as if by std::basic_string_view<CharT, Traits> sv = t;, then initializes the string with the contents of sv, as if by basic_string(sv.data(), sv.size(), alloc). This overload only participates in overload resolution if std::is_convertible_v<const StringViewLike&, std::basic_string_view<CharT, Traits>> is true and std::is_convertible_v<const StringViewLike&, const CharT*> is false.

Since both conditions hold for std::string_view itself, we can write the call to loadData as simply:

loadData( std::string( symbol.strVw() ) );
Sign up to request clarification or add additional context in comments.

2 Comments

You said implicitly, but it is explicit, right?
@markus - The string c'tor is, obtaining a string_view is done implicitily inside this c'tor.
4

If you have some string_view in C++ that you want to convert into string format (so you can return to a function after doing all your analyses, for example), you can make that change by doing this:

string_view sv;
string s = {sv.begin(), sv.end()};

Going the other way, to get a string_view from a string (so to get a pointer to that string) you can do this:

string s;
string_view sv = string_view(s);

Note that substring and a variety of other operations can be performed on string_view just as on string.

4 Comments

Doesn't this make a full copy of the string though? The primary purpose of string_view is to avoid doing exactly that.
@Roflcopter4 a std::string is a value type owning the memory for the string. Instanciating the std::string has to do a full-copy, because that is exactly what is requested by using this type.
Why not std::string_view sv{ s }; or auto sv = std::string_view{ s };
Prefer data() and size() for accuracy. Check "Maxim Egorushkin" answer for this.
1

Is the first method correct?

It is, since strVw returns identical string_views: they all point to the same m_V and have the same size.

The correctness here depends on how strVw is implemented.

or I must use the second one?

I would create a conversion function:

inline std::string as_string(std::string_view v) { 
    return {v.data(), v.size()}; 
}

And use that:

loadData(as_string(symbol.strVw()));

This method is safe regardless of strVw implementation.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.