fenbf / cppstories-discussions

4 stars 1 forks source link

2022/init-string-options/ #94

Open utterances-bot opened 2 years ago

utterances-bot commented 2 years ago

20+ Ways to Init a String, Looking for Sanity - C++ Stories

C++ is famous… or infamous for its complex initialization syntax. In this article, I’ll show you around 20 ways to initialize simple std::string variables. Can we somehow make it easier to understand? Default values   Have a look: void foo() { std::string str0; std::string str1 {}; } We have two local variables (with automatic storage duration), str0 is default initialized, while str1 is value initialized.

https://www.cppstories.com/2022/init-string-options/

mariusbancila commented 2 years ago

Since you explicitly said 20+ ways in the title, in my opinion, it would be easier to follow these ways if they were numbered somehow.

2kaud commented 2 years ago

For a variation on a theme to init a string:

#include <string>
#include <iostream>

int main() {
    const char a { 'a' }, b { 'b' }, c { 'c' };
    const std::string s { a, b, c};

    std::cout << s << '\n';
}

where you can init a string from different chars (either variables or consts).

Also note the .assign() member function which allows the contents of an existing string to be set using the same formats as for the constructor.

#include <string>
#include <iostream>

int main() {
    std::string s { "qwerty" };
    const char a { 'a' }, b { 'b' }, c { 'c' };

    s.assign ({ a, b, c });

    std::cout << s << '\n';
}

If you follow AAA (almost always auto) then:

#include <string>
#include <iostream>
using namespace std::string_literals;

int main() {
    const auto s { "qwerty"s };

    std::cout << s << '\n';
}
2kaud commented 2 years ago

Also note that the meaning of:

auto a {xyz};

changed between C++11 and C++14. With C++11 it means a is of type std::initializer_list<decltype(xyz)> with one value of xyz, In C++14 it means a is of type decltype(xyz) with one value xyz.

In both cases use of auto with list initialization of more than one value produces a type of std::initialization_list

2kaud commented 2 years ago

For ways to initialise, consider:

int no;          // Valid but bad as not initialized!
int a {};
//int b ();     // Not a definition - function declaration (Most Vexing Parse!)
int c { 0 };
int d = 0;
int e = { 0 };
int f (0);
auto g { 0 };
auto h = { 0 };
auto i = 0;
auto j (0);
auto k { int(0) };
auto l { int{0} };
auto m { int{} };
auto o { int() };
auto p (int(0));
auto o (int { 0 });
auto q (int {});
auto r (int());
auto s = int(0);
auto t = int();
auto u = int {};
auto v = int { 0 };
auto w = { int(0) };
auto x = { int{0} };
auto y = { int{} };
auto z = { int() };
fenbf commented 2 years ago

Since you explicitly said 20+ ways in the title, in my opinion, it would be easier to follow these ways if they were numbered somehow.

Hi Marius, have a look at strN variables, they are numbered from str0 till str20

mariusbancila commented 2 years ago

Ah, the name format of the variables is something I didn't actually catch. I paid more attention to the initialization part. But that's good.

2kaud commented 2 years ago

Based upon my init comment above, for std::string then:

#include <iostream>
#include <string>
using namespace std::string_literals;

int main() {
    std::string s0;
    std::string a {};
    //std::string b ();     // Not a definition - function declaration (Most Vexing Parse!)
    std::string c { "s" };
    std::string d = "s";
    std::string e = { "s"};
    std::string f ("s");
    std::string g { "s"};
    auto h = { "s"s};
    auto i = "s"s;
    auto j ("s"s);
    auto k { std::string("s"s) };
    auto l { std::string{"s"s} };
    auto m { std::string{} };
    auto n { std::string() };
    auto o (std::string("s"s));
    auto p (std::string { "s"s });
    auto q (std::string {});
    auto r (std::string());
    auto rr (std::string);
    auto s = std::string("s"s);
    auto t = std::string();
    auto u = std::string {};
    auto v = std::string { "s"s};
    auto w = { std::string("s"s)};
    auto x = { std::string{"s"s}};
    auto y = { std::string{} };
    auto z = { std::string() };

}

Without using every possible std::string constructor combination, have I missed any?

tbetten commented 2 years ago

I think it's pretty simple. Use braces except when you want a specific, non initializer list constructor. In that case use parens.

YinYongHongYork commented 2 years ago

int x; // zero initialization, but please don't try!

It's a default initialization and it's not static storage or thread storage, so It can NOT be zero-initialized.

2kaud commented 2 years ago

x is an int global variable with static duration and hence is zero-initialised by default as it has no defined initializer.

jmccabe commented 1 year ago

In your default values section, you suggest using the form std::string str {} to initialise an empty string, then go on to reference https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-always where there are two examples of std::string usage, neither of which explicitly initialise their values in this way.