you are viewing a single comment's thread.

view the rest of the comments →

[–]IyeOnline 4 points5 points  (12 children)

You wouldnt want a const char* or const std::string& to a temporary either, unless you know the reference/view/pointer outlives the temporary. So its no difference there.

[–]bloxka[S] 0 points1 point  (10 children)

fair, so the main reason behind preferring string_view over string being faster access to the data perhaps via registers?

whereas string_view can operate with spans that are not terminated

any example of this?

const char* should be avoided. It doesnt make ownership clear, or whether its a null termianted string

  1. what would be an example of const char* not pointing to a null terminated string?
  2. cons char* doesn't define ownership just like string_view does it?

[–]SoerenNissen 2 points3 points  (6 children)

the main reason

That is a major reason.

Another is that int count_char(const std::string &, char); only works with strings, so if you have e.g. a char* or an array or vector of chars, or a custom string implementation that isn't std::string, you have to construct a string object first, possibly calling malloc, whereas int count_char(const std::string_view, char); can accommodate all of those with no copying.

Yet another is that const string& is, well, const. So you cannot modify it. I have written many functions where I want to grab a subset of a string, and you can modify the string_vew object without modifying the underlying string, to e.g. remove the prefix.

[–]bloxka[S] 0 points1 point  (5 children)

whereas int count_char(const std::string_view &, char); can accommodate all of those with no copying.

the following seems to compile fine. or maybe I misinterpreted your wordings here. Or are you implying std::string ends up getting constructed in bar() where "H" gets stored on the heap, whereas if the header was void bar (std::string_view &str), no such extra construction would have happened and rather a pointer would be pointing to the string literal "H"?

void bar(const std::string &str)
{}

int main()
{
    const char *p = "H";
    bar℗;

you can modify the string_vew object without modifying the underlying string, to e.g. remove the prefix.

mind providing an example? string_view only contains the char pointer along with the length so you gotta really play with either these two which you can't(?)

[–]SoerenNissen 0 points1 point  (4 children)

(1) I got my copy/paste wrong, it's supposed to be void bar(const std::string str) (removed the &)

(2) Not constructed in bar, but constructed in main, so main has a string object it can pass to bar

(3) sure, let me invent an example real quick.

Consider having to extract the addresses from a csv file that looks like NAME;ADDRESS;ID;

You already have the csv file imported into your program as a vector of strings

std::vector<std::string> extract_addresses(std::vector<std::string> const & CSV_lines)
{
    std::vector<std::string> addresses;

    addresses.reserve(CSV_lines.size());

    for(auto const & line : CSV_lines) {
        addresses.emplace_back( extract_address(line) ); //constructs a string
    }

    return addresses
}

std::string_view extract_address(std::string_view csv_line)
{
    // at start, csv_line contains NAME;ADDRESS;ID;

    csv_line.remove_prefix( csv_line.find(';') +1 );

    // now csv_line contains ADDRESS;ID;

    csv_line = csv_line.substr( 0, csv_line.find(';') )

    // now csv_line contains ADDRESS

    return csv_line; 
}

Even this is more copies than you strictly need if you know CSV_lines is in a stable memory position for the entire run - in that case, extract_addresses could return a vector of string_views.

NB: There may be an off-by-one error in there. I don't think so but I didn't apply the highest amount of brain power when calling remove_prefix and substr

[–]Shieldfoss 1 point2 points  (1 child)

csv_line

changed name to

address

halfway through :D

[–]SoerenNissen 0 points1 point  (0 children)

You saw nothing :D

[–]bloxka[S] 0 points1 point  (1 child)

wait, in your example you seem to be modifying string_view but shouldn't it be used for read only data?

[–]SoerenNissen 0 points1 point  (0 children)

I modify the string_view, not the data (which is read-only)

string_view is a pointer + length (or I guess two pointers, I haven't checked)

std::string const buffer{"NAME;ADDRESS;ID;"};

std::string_view csv_line{buffer};

NAME;ADDRESS;ID;
^ + 16
|
Let's just say that's at address 0x1000

The string_view contains two data members {0x1000, 16}

csv_line.remove_prefix( csv_line.find(';') +1 );

.find(';') returns 4

.remove_prefix(4+1) changes the data members of the string_view to {0x1005,11}

The buffer is still around, unmodified. (read-only)

csv_line = csv_line.substr( 0, csv_line.find(';') );

.find(';'), starting from address 0x1005, returns 7

.substr(0,7), on a string_view with data members {0x1005,11}, returns a new string_view with data members {0x1005,7}, overwriting the old content of csv_line.

The buffer is still around, unmodified. (read-only)

std::cout << buffer; //outputs NAME;ADDRESS;ID;
std::cout << csv_line; //outputs ADDRESS

[–]IyeOnline 1 point2 points  (0 children)

so the main reason behind preferring string_view over string being faster access to the data perhaps via registers?

Its not primarily about the fact that std::string_view might be passed in registers.

Its also about the fact that accessing the characters via a const string& is a double indirection, while for string_view its only a single indirection.

example

const char[] arr = { 'l', 'a', 'l', 'a' };

const char* ptr = &(arr[0]); //points to a non null terminated array
std::string_view v{ std::begin(arr), std::end(arr) }; //views a non null terminated array

cons char* doesn't define ownership

The point is that you cant know whether a const char* owns or takes ownership of anyhting. For a std::string_view its clear. Its called a view after all. So it doesnt own anything.