Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::string s1 {"Modern C++", 3} vs std::string s1 {str, 3}

Tags:

c++

string

c++17

The output of the following code confuses me:

const std::string str = "Modern C++";

std::string s1 {"Modern C++", 3};
std::string s2 {str, 3};

std::cout << "S1: " << s1 << "\n";
std::cout << "S2: " << s2 << "\n";

output:

> S1: Mod
> S2: ern C++

Can anyone explain this result?

like image 952
dbenarfa Avatar asked Jan 01 '21 22:01

dbenarfa


People also ask

What is the difference between std::string and string?

std::string is the string class from the standard C++ library. String is some other string class from some other library. It's hard to say from which library, because there are many different libraries that have their own class called String.

How can I compare two strings in C++?

In order to compare two strings, we can use String's strcmp() function. The strcmp() function is a C library function used to compare two strings in a lexicographical manner. The function returns 0 if both the strings are equal or the same. The input string has to be a char array of C-style string.

Can you use std::string in C?

A std::string_view can refer to both a C++ string or a C-string. All that std::string_view needs to store is a pointer to the character sequence and a length. std::string_view provides the same API that std::string does, so it is a perfect match for C-style string literals.

Should I use std::string?

Use std::string when you need to store a value. Use const char * when you want maximum flexibility, as almost everything can be easily converted to or from one. Save this answer.


4 Answers

From:

https://en.cppreference.com/w/cpp/string/basic_string/basic_string

std::string s1 {"Modern C++", 3};

Uses the following constructor:

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

So takes 3 chars to get Mod.

std::string s2 {str, 3};

will use the following constructor:

basic_string( const basic_string& other,
          size_type pos,
          const Allocator& alloc = Allocator() );

So taking the string from position 3 onwards giving : ern C++.

like image 177
0RR Avatar answered Oct 22 '22 07:10

0RR


One is calling string(char const*, count), the other string(string const&, pos).

One gets the first 3 characters from a buffer, the other all the characters after the 3rd one.

This is because C++ has raw character buffers and std strings. "this is not a std::string". "this is a std string"s, std::string so_is="this";.

std::string is more than 30 years old, and it was added to the C++ language without sufficient care (unlike the STL, which went through more iterations before being added).

Its interface is honestly too rich, and you can run into stuff like this; multiple overloads that lead to confusing results.

like image 34
Yakk - Adam Nevraumont Avatar answered Oct 22 '22 07:10

Yakk - Adam Nevraumont


Can anyone explain to me why is that?

That is due to std::string having constructors which it really shouldn't (@ORR explained the details). And it shouldn't have these constructors because:

  1. Their effect is easily achievable using named constructor idioms / std::string methods and existing constructors - at no extra cost (in C++11 at least), and
  2. It is not obvious and trivial to understand how the constructor arguments are used from just looking at the constructor invocation.

This is not the only case in the standard library with such undersirable (IMHO) constructors; std::vector is (in)famous for too much constructor variety and confusing/misleading constructor semantics.

Life lessons:

  • Skimp on constructors; not every commonly-used bunch of values used to construct an object of your class deserve their own constructor;
  • instead, use named constructor idioms.
  • Have your code reviewer or some other less-biased party read an invocation of your constructors, to gauge whether the meaning of each one is obvious enough.
like image 7
einpoklum Avatar answered Oct 22 '22 07:10

einpoklum


Incase you want to get the same output like

Mod for s1

Mod for s2

You can use a char pointer for str e.g

char * str = "Modern C++";

std::string s1 {"Modern C++", 3};
std::string s2 {str, 3};

std::cout << "S1: " << s1 << "\n";
std::cout << "S2: " << s2 << "\n";

The output

 Mod

 Mod
like image 3
kelly43 Avatar answered Oct 22 '22 07:10

kelly43