Std: :String S1 {"Modern C++", 3} vs Std: :String S1 {Str, 3}

Std: :String S1 {"Modern C++", 3} vs Std: :String S1 {Str, 3}

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?

10

4 Answers

From:

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++.

4

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.

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.

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
4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Chloe Bennett
Author

Chloe Bennett

Chloe Bennett explores the intersection of pop culture, streaming entertainment, digital trends, and contemporary lifestyle. Her weekly commentary reaches thousands of culture enthusiasts.