std::string_view

Started by
3 comments, last by rnlf_in_space 6 years, 5 months ago

Can string_views be used in combination with setters?

I would like to have something like the code below. Unfortunately, my constructors are ambiguous for the second invocation. The view is capable of reducing the number of methods, std::string, C string, but could it be used as well in combination with move semantics? Or is the view solely intended for "you may look at the string, but you are not allowed to own it."?


#include <iostream>

#include <string>
#include <string_view>
using namespace std;

struct Str {
    
    explicit Str(string_view str)
        : m_str(str) {}
    explicit Str(string &&str)
        : m_str(std::move(str)) {} 
    
    string m_str;
};

int main() {
    string a = "a";
    
    Str as = Str(a);
    Str bs = Str("b");
}

 

🧙

Advertisement

string_views never own. The ambiguity comes form the fact that you are creating a temporary object out of your string-literal. The compiler cannot figure out which of the two possibilities you want, either a string_view which will then be used to construct a new std::string in your constructor, or create a temporary string object and then move-construct your member from that.

I don't see a good reason to use string_view here, you'll have to make a copy sooner or later anyway, why not create it at the call site and forgot about all the difficulties you are facing now?

1 hour ago, rnlf_in_space said:

I don't see a good reason to use string_view here, you'll have to make a copy sooner or later anyway, why not create it at the call site and forgot about all the difficulties you are facing now?

But then I will have again three constructors:

explicit Str(const string &str)

explicit Str(string &&str)

explicit Str(const char *str)

Note that I could remove the last one. Makes me actually wondering whether the last one is actually needed (i.e. can result in some performance advantage when using C strings directly)? The C string will result in the implicit creation of a temporary string which will be passed as an rvalue reference, right?

🧙

Yeah, this can all lead to an explosion of overloads very quickly. I think passing an std::string by value and then moving from that string to initialize your members has the best performance/effort ratio.
This talk by Nicolai Josuttis illustrates the problem very nicely, even if for slightly more complex cases:

In your case I'd probably just go with Str(std::string str) : m_str(std::move(str)) {}, that way you create one copy of your string at the call site and then just use the (comparatively) cheap move constructor to initialize your member.

std::string only has an explicit constructor that takes a string_view though, so if you'll either have to create the string object at the call site, too, or overload with something like

Std(std::string_view v) : Str(std::string(v)) {}.

I'd prefer the first option (making the copy explicit at the call site) because it doesn't hide the extra allocations and memcpy.

This topic is closed to new replies.

Advertisement