r/cpp • • Dec 19 '23

Obsessed with {} initialization?

I'm on a discord where everyone seems to be obsessed to use brace initialization everywhere.
My motto is: Use things rarely, only when needed, to express that right there the feature does something important.
Personally I would completely advocate against using it for simple stuff like
double tax{0.09*price};

or just int{0}

probably a hornets nest

4 Upvotes

118 comments sorted by

50

u/jedwardsol const & Dec 19 '23

What do you advocate using instead, and why is that better?

18

u/serviscope_minor Dec 19 '23

What do you advocate using instead

=

and why is that better?

There's a reason C++ uses = for assignment and no one wants to change it.

52

u/Intrepid-Treacle1033 Dec 19 '23

https://herbsutter.com/2013/05/09/gotw-1-solution/

"Common Mistake: This is always initialization; it is never assignment, and so it never calls T::operator=(). Yes, I know there’s an “=” character in there, but don’t let that throw you — that’s just a syntax holdover from C, not an assignment operation. "

14

u/serviscope_minor Dec 19 '23

Eh so?

If I have

int x=5;

x is now 5. In a standardese language sense, x is initialised with 5, but it has the same practical purpose (and reads the same) as any subsequent assignments to x.

Having the initialisation of x look different to subsequent assignments is an exercise in putting the language's needs above the human's.

33

u/HolyGarbage Dec 19 '23 edited Dec 19 '23

It doesn't make a difference for integral types, but for classes, and in particular where copy and move constructors and assignment operators have user provided implementations it does make a difference.

If you're assigning where you meant to be initializing you could either a) assign to uninitialized memory which is potentially undefined behavior depending on the class definition, or b) first default constructing followed by an assignment which could incur additional performance costs.

Note, I'm not saying that using = for initialization in your example would do this, but was simply demonstrating the importance of the distinction between initialization and assignment, which using the = for initialization makes less clear. The feature of using braces for all kinds of initialization is called "uniform initialization" for a reason, to make it clear directly by the syntax what operation you're invoking.

1

u/serviscope_minor Dec 19 '23

It's not a high point to be sure. Uniform is, well, uniform in the language. The caveat is that it makes the code less nice to read, because you have two different syntaxes for a variable getting a value.

3

u/bromeon Dec 20 '23

I don't know why this is getting downvoted. It's sometimes good to take some distance from C++, look at the 4 different initialization syntaxes and then see how other languages (including C) keep things simpler.

The "uniform initialization syntax" introduced in C++11 was always controversial, and it in fact fails its promise to truly unify things (see e.g. std::initializer_list ambiguity). It's difficult to universally advocate the one true initialization syntax, each has some pitfalls.

3

u/serviscope_minor Dec 20 '23

I don't know why this is getting downvoted.

Probably because it's not engaging in language pedantry (guaranteed way to get downvotes here). I know initialization in C++ is a nuanced topic, but I reckon {} everywhere is letting the tail wag the dog. Look at the responses to my earlier post: I pointed out that = is used for assignment and no one wants to change it, and got hit with a gale of "initialization is not assignment". The latter is of course technically true, but from a higher level view, above C++, assigning to a new object and assigning to an existing one don't really differ in a lot of ways. It's all just assignment.

It's a useful thing to have for sure ad makes generic code easier to write, avoids vexing parses and so on, but it just doesn't read nicely compared to =, so I use = where I can easily do so and {} for everything else (unless I slip into old habits and use ()).

1

u/panoskj Dec 22 '23

where I can easily do so and {} for everything else (unless I slip into old habits and use ()

Or unless you want to initialize a std::vector calling the constructor with the size parameter or something like that. We are back to square one.

1

u/serviscope_minor Dec 22 '23

Ha! Yes, not a high point of C++ to be sure!

2

u/HolyGarbage Dec 20 '23

you have two different syntaxes for a variable getting a value.

That's exactly the point. Because assignment and initialization is not the same thing.

1

u/serviscope_minor Dec 20 '23

And my point is that's putting the needs of the language ahead of the programmer.

People like = for assignment and initialization is from a higher level perspective than C++ a kind of assignment.

3

u/HolyGarbage Dec 20 '23

No it's not. Both initialization and assignment are things the programmer should be aware of. = is already used for assignment in C++, your example however used = for initialization, not assignment. I'm saying that can be confusing since it looks like an assignment.

1

u/serviscope_minor Dec 20 '23

I think we are taking at crossed purposes. I understand the grammar. I mean the assignment/initializing thing is specific to C++ not a general thing about programming.

= reads better and is (when it works) more regular since = sets values in any context.

→ More replies (0)

13

u/Intrepid-Treacle1033 Dec 19 '23

Eh so?

Nothing, your code you are the boss. The standard has multiple ways, and those ways has different nuances. If that matter practically is up to you/project. The languange needs thing i dont understand what you mean..

3

u/jones77 Dec 19 '23

It's so you can communicate properly with other C++ programmers.

It does not have the same practical purpose as assignment because you could mess up your code and not understand why it is broken.

43

u/SuperV1234 https://romeo.training | C++ Mentoring & Consulting Dec 19 '23

There's a reason C++ uses = for assignment and no one wants to change it.

And that's exactly why {} should be preferred for initialization, because people still confuse assignment and initialization in 2023.

1

u/Pretend-Guide-8664 Dec 19 '23

I suppose you don't want me to ask what the difference is then...

Technically I think one writes to memory a new value (initialization), and the other either copies a value, copies a pointer, or moves data (assignment).

Is there a chart for the yes and nos of this?

4

u/joahw Dec 19 '23

That is correct. For objects if you accidentally do an assignment instead of initialization you are likely to do unnecessary copies, moves and/or destruction of temporaries which could have performance implications.

3

u/TheMania Dec 19 '23

Importantly, assignment may reuse the values already in that location. No need to write the vtable, might be able to reuse heap allocations and just overwrite the values, etc. A pretty sure way to break things sometimes when used if you actually meant to use a constructor instead.

So it is good to think of them as different imo.

7

u/jedwardsol const & Dec 19 '23

= is for assignment,

/u/DoctorNuu is saying don't use for {} for initialisation. And it was changed, or at least added to; we can now use =, () or {} for initialisation.

3

u/trvlng_ging Dec 19 '23

EVERYONE wanted to change it, but backward compatibility made that impractical. assignment-style initialization is a thowback to C compatibility. It is very hard to teach, because from a grammar persspective, "=" in initialization is a punctuator, while in an assignment, it is an operator. The parsing rules for the punctuatior are different than to precedence rules for the operator. When someone is learning C++, they often conflate parse rules with precedence rules, and this is one of those that causes a lot of confusion. I get why C++ coudn't have it removed easily, but I find that using an enterprise rule to avoid assignment-style initialization has improved how quickly new C++ programmers come up to speed. Using constructor-syntax initialization often leads to the vexing parse, so our default is {}. And we have never seen a problem with parsing it as an initializer list inappropriately.

5

u/guepier Bioinformatican Dec 19 '23 edited Dec 19 '23
auto x = type();

Is better1 because it avoids accidentally invoking a std::initializer_list constructor. In generic code, {} is pretty much a no-go for this reason.

Furthermore, using auto avoids the most vexing parse and has other advantages (see GOTW 95 — tl;dr: it has the potential of drastically improving readability by making declaration syntax more uniform).

Consistently using this style of declaration avoids all the problems of the alternatives (both () and {}).


1 When used in conjunction with the appropriate compiler settings to avoid implicit narrowing conversions!

15

u/HolyGarbage Dec 19 '23

Except that it's not clear if type is a type or a function. In some languages the constructor is a distinct free function so it's the same thing, but not in C++ unfortunately.

7

u/guepier Bioinformatican Dec 19 '23

I can see how this could theoretically be a problem but in my entire career of writing C++, confusion between a type and a function has never been an actual problem in an initialisation. In fact, it should arguably not matter whether type() refers to a constructor or function call here.

And what I’m suggesting is hardly arcane, some of the most prominent C++ experts are also proponents of this style (Herb Sutter first and foremost, of course). I’m therefore surprised it’s met with such negativity here.

1

u/HolyGarbage Dec 20 '23

I wasn't trying to negative, just adding to the discourse, by pointing out a case where it is not ideal.

3

u/guepier Bioinformatican Dec 20 '23

Yes, that’s appreciated. I didn’t mean your comment specifically, but at the time of writing my own comment had been massively downvoted (now somewhat recovered).

0

u/[deleted] Dec 20 '23

[deleted]

1

u/guepier Bioinformatican Dec 20 '23 edited Dec 20 '23

The link I gave was about (A)AA style, not () vs {}. However, it’s a severely dated article (ten years old, from the C++11 era — it still calls the concept “AAA”, but it’s now simply “AA” since there are no longer any exceptions!) and I think Herb Sutter has changed his opinion on brace initialisation since then — however, I don’t have a reference for this claim, and I might misremember.

That said, if you use AA there’s even less reason to use {} over (), since the most vexing parse no longer figures into the equation, and the implicit narrowing conversion mentioned in your quote can be caught by compiler diagnostics.

38

u/Intrepid-Treacle1033 Dec 19 '23

God old post from a guy that has some cpp experience.

https://herbsutter.com/2013/05/09/gotw-1-solution/

int x{}; "...it always initializes the variable, and is never ambiguous with a function declaration. No vex, no fuss, no muss..."

1

u/guepier Bioinformatican Dec 19 '23

This is a real problem, but it goes away completely when using AA style (auto x = int(); … or, auto x = 0;).

6

u/Intrepid-Treacle1033 Dec 19 '23 edited Dec 19 '23

I like auto, its like having a Dog you got when it was a puppy. It follows you wherever.

3

u/jk_tx Dec 19 '23

It has its own issue though, lots of folks still tend to get confused between auto and auto& (or just forget to type the '&'), which can also cause unintended consequences and bugs.

4

u/ThePillsburyPlougher Dec 19 '23

It can also just make code difficult to read.

5

u/DanielMcLaury Dec 20 '23

so can

std::unordered_map<uint64_t, Data>::iterator it = data.find(index);

-8

u/DoctorNuu Dec 19 '23

good find, shows that you have to know what you're doing

54

u/embeddedsbc Dec 19 '23

The reasoning should be the other way around. Almost always use brace initialization. It avoids automatic narrowing. Use copy assignment for single values or auto. But it's a much better default than the alternatives.

24

u/guepier Bioinformatican Dec 19 '23

On the flip-side, brace initialisation can trigger an unexpected constructor taking an initialiser list. This is arguably more dangerous than narrowing conversions with (). It definitely leads to plenty of gotchas.

I am in the camp (and I know I am not alone!) lamenting the missed opportunity with uniform initialisation. I thought {} was it, but because of the std::initializer_list issue, it isn’t. For this reason, I (and others) entirely reverted to () after an initial honeymoon period with {}. Oh, and I use -Wconversion -Werror so () is more strict than {}.

2

u/enigma2728 Dec 20 '23

Well today I learned. Kind of sad; I liked the idea of just being able to use brace initialization everywhere to avoid having to think about all the minutia of initialization.

Is this problem easily demonstrable in godbolt, or have a link to an example of where this becomes a problem?

std::vector doesn't seem to have an issue with braced initializer list. https://godbolt.org/z/scx1rs8s4

Perhaps it is only an issue if there is also a ctor that takes arguments of same type? It does seem like init list gets preferred over specific ctors, from my testing. https://godbolt.org/z/fGsed6o9M

    #include <iostream>
    #include <initializer_list>
    struct CtorCompetition
    {
        CtorCompetition(int x, int y)
        {
            std::cout << "2-arg ctor" << std::endl;
        }
    
        //CtorCompetition(int x, int y, int z)
        CtorCompetition(std::initializer_list<int> list)
        {
            std::cout << "init list ctor" << std::endl;
        }
    };
    int main()
    {
        CtorCompetition TwoArgObject{1, 2}; //uses init list, not 2arg
        CtorCompetition ThreeArgObject{1, 2, 3}; //uses init list
    
        //CtorCompetition TwoArgObject(1, 2); //uses 2 arg
        //CtorCompetition ThreeArgObject(1, 2, 3); //doesn't compile
    }
    Program returned: 0
    init list ctor
    init list ctor

Is the above what you are referring to?

I feel like perhaps I can still just use braced initializer with the expectation that initializer lists are preferred to specific constructors.

1

u/equeim Dec 22 '23

If the vector's element type can be implicitly constructed from a vector, then std::vector vec{otherVec} will create a vector with a single element of otherVec, not copy it.

2

u/NilacTheGrim Dec 23 '23

Yeah for actual class types () initialization is the best way to this day. The ambiguity {} introduces with std::initializer_list is a huge foot-gun waiting to go off.. and I tend to avoid foot-gun stuff as best I can.

1

u/[deleted] Dec 22 '23

It avoids automatic narrowing.

It does not.

https://godbolt.org/z/zqTGanqjE

-13

u/DoctorNuu Dec 19 '23

where does this fear of narrowing come from?
The core guidelines has a line int y = 7.9; // OK: y becomes 7. Hope for a compiler warning
If your compiler does not offer this warning... well... get a better one

13

u/syyyr Dec 19 '23

It should be an error by default. Also, the warning is not enabled by default (I think).

0

u/joeshmoebies Dec 19 '23

/WX /W4 on msvc -Werror on clang/gcc

Problem solved

4

u/syyyr Dec 19 '23

Does it solve the problem it not being the default?

2

u/DanielMcLaury Dec 20 '23

How does the default matter to you? Are you constantly creating new projects by writing a single c++ source file, saving it, and then immediately compiling it directly from the command line?

-1

u/syyyr Dec 20 '23

No, I'm using {}.

0

u/joeshmoebies Dec 19 '23

I'm not sure what your point is. If you want narrowing conversion assignments to be errors, you can have them.

As far as the default settings being a problem, apparently not everyone thinks so or Microsoft and the developers of GCC and Clang would change them.

I don't get complaining about something when you can have it exactly how you want.

1

u/syyyr Dec 20 '23

I don't get complaining about something when you can have it exactly how you want.

Yes, with {}.

4

u/jotux Dec 20 '23

https://godbolt.org/z/WG7bcKdcE

Try it on clang and gcc.

Better yet, pick some moderately-sized codebase and change every single variable initialization to uniform initialization syntax and see how many narrowing conversions are happening with no warning. That's what made me switch to 100% '{}'.

5

u/erreur Dec 19 '23

My fear comes from the memory of dealing with data loss in production caused by some accidental narrowing. I used to think this was overblown but now I use brace initialization everywhere and use every flag the compiler supports to disable all implicit conversions of any kind.

14

u/TheFryedMan Dec 19 '23

It's also called uniform initialization. It's supposed to be a single way to initialize everything. It also avoids implicit conversions, which can help avoid bugs. Also, explicitly calling {} will avoid uninitialized values, which can cause undefined behavior. This also avoids something called "the most vexing parse." This issue causes the compiler to think you are calling a function instead of initializing a value. In summary, it avoids a lot of issues and provides a uniform syntax for initialization.

21

u/guepier Bioinformatican Dec 19 '23

It's also called uniform initialization.

And that was a great promise, but unfortunately it is simply a lie, thanks to std::initializer_list.

12

u/shahms Dec 19 '23

It's also called "unicorn" initialization as a play on this misleading moniker and because, much like unicorns, a single initialization syntax which works reliably in C++ does not exist.

1

u/NilacTheGrim Dec 23 '23

It also avoids implicit conversions, which can help avoid bugs.

True, except when it doesn't due to the existence of std::initialize_list !!

-6

u/DoctorNuu Dec 19 '23

could have been a good feature

11

u/aruisdante Dec 19 '23

The core guidelines has a whole section on when and why you should use brace initialization. I think its recommendations are pretty much correct, which is “most of the time”, especially if you don’t use -Wcoversion, -Werror. int a{10} definitely looks worse than int a = 10, but that’s why you should be doing auto a = 10; anyway, so you only state your type once.

11

u/ponchietto Dec 19 '23

I don't get why auto a = 10; would be better thant int a = 10;

I prefer being explicit rather that have the reader (including myself) deduce the type (extra effort) and very easily use the wrong type (10 vs 10.0 vs 10.0f vs 10U).
The compiler will complain if I am not consistent.

8

u/aruisdante Dec 19 '23 edited Dec 19 '23

The compiler will in fact not complain if you use it wrong without Wconversion, that’s the point the guidelines are talking about.

int narrowing = 4294967296;
unsigned int signed_loss = -1;
int float_conversion = 11.1;
int arbitrary_conversion = foo(); // foo returns double;

Those will all compile without warning if you don’t have Wconversion enabled. Whereas if you brace initialize them, the compiler will warn even without -Wconversion.

Now of course you should just have Wconversion turned on, and then life is easier, and you can use = assignment safely. One of the constant frustrations in my day job is that AutoSAR and MISRA both ban = initialization anyway (and, thanks to AutoSAR’s terrible writing, also it also technically bans auto completely, as it sates = initialization must be used for auto immediately after stating brace initialization must be used for all variables). Thankfully MISRA2023 takes a more enlightened view here.

In terms of being explicit with what type you want: the auto a = form is explicit. You want the type, and exactly the type, to the right of the assignment. For example, if I see:

int a = 11.1;

How do I know which was intended? Did the author mean for that literal to be 11? Did they mean for the type of a to be float or double?

Now you can definitely go overboard here, but the general guidance of “only state your types once” serves pretty well.

1

u/Nobody_1707 Dec 23 '23

One nice oddity of concepts is that you can write std::same_as<int> auto i = x; and it will prevent any implicit conversions whatsoever.

0

u/ponchietto Dec 19 '23

I have nothing against braces, I was just using the example above, my problem is auto (in this case).

"How do I know which was intended? Did the author mean for that literal to be 11?" The author made a mistake, probably on the right, I don't see the point, though.

It is just far easier for human beings to read the type in front of the variable rather than deduce it from the right.
Moreover you might not have a number, you could have a constant, a function or an expression on the right, when does it becames non obvious enough?

4

u/bert8128 Dec 19 '23

If you specify the type in the right, don’t specify it on the left, unless you want it to be different.

1

u/shahms Dec 19 '23

And Abseil has a whole section on the pitfalls of brace initialization: https://abseil.io/tips/88

Initialization C++ is absurdly convoluted and subtle. Braced initialization solves some problems with the other ways of doing it, but introduces a whole raft of its own problems. There is no single "always good" way of performing initialization in C++, sadly, and the core guidelines do a serious detriment here by pretending that there is.

5

u/aruisdante Dec 19 '23

Yes, and for the most part I agree with Titus too, but he’s concerned more with brace vs paren initialization than brace vs = initialization. I’ve in fact used that very article to try and overturn silly “always use {} initialization” rules at 2 different companies in the automotive space.

I think that’s the biggest issue with all of the guidelines, they don’t distinguish between separate concerns:

  • I don’t want implicit conversions for arithmetic types

  • I don’t want implicit conversions for structures which have non-explicit constructors, or which consume arithmetic types.

  • I have Wconversion turned on, should I care?

The last one can be particularly subtle. Wconversion ignores implicit conversions that happen inside the stdlib, because it has to as the stdlib is full of them. There are certain types which have templated constructors (like, say, std::optional), and so if you parens-construct them in a non CTAD context but which would result in a conversion that should be caught, it will not happen: from the perspective of Wconversion the ctor that was called was the converting constructor, which consumes the actual type, and then inside the stdlib a narrowing happens, but that’s ignored. If you brace initialize them on the other hand, the implicit conversion is not allowed, and Wconversion fires.

You’re absolutely right that the whole subject is a mess. Unfortunately teaching people all the ins and outs of what to do isn’t a reliable thing to do at scale. So most safety critical coding standards pick one, and unfortunately they tend to pick the most restrictive one even if it introduces a host of other, potentially much worse classes of bugs. The core guidelines doesn’t really have the same excuse, but it’s guideline also is poked through all kinds exceptions, and it’s also a prefer, not a must. And I agree with the guideline’s suggestion that brace initialization should be preferred unless there is a good reason to not use it. I do not agree with AutoSAR’s requirement that it must be used.

1

u/shahms Dec 19 '23

The tip specifically discusses the differences between all three forms of initialization, including = and says to prefer copy initialization.

1

u/Intrepid-Treacle1033 Dec 19 '23

"And" ?

Abseil is an article about an article. In the bottom of Abseil article it states "Perhaps the best overall description of the issue is Herb Sutter’s GotW post. (link)"

And i agree, Herbs article is good.

1

u/shahms Dec 19 '23

Wat. The Abseil tip includes a description of the issues and recommendations. It then suggests reading Herb's article as a follow-up for additional context.

2

u/Intrepid-Treacle1033 Dec 19 '23

In my effort to go to the bottom and really learn initialization i read among others the Absail and did not get it, but there i got the Herb link and that one nailed it for me. So for me the Absail was just an distraction hence my article about an article comment. But ok reading it again i see a angle, and i did not really mean article about an article as a negative thing.

-4

u/DoctorNuu Dec 19 '23

Oh, now I see where it's coming from.
Not particularly well written imho.

4

u/manni66 Dec 19 '23

At least they provide a reason, unlike you.

-2

u/DoctorNuu Dec 19 '23

I wonder if they recommend enabling lots of warnings, including this one

5

u/mredding Dec 19 '23

Obsessed with {} initialization?

Obsessed with not? What about narrowing conversions?

The standard committee largely can't and won't break old code. They can't add a constraint to assignment, but they can add a new initialization. All they can do is provide a migration path forward.

All the new features are meant to fix problems in the past. Your conservative approach is benefiting you... how?

And this is how standards and practices stagnate. You have to look at the present and be ready for the future. We need a language and a standard that meets the needs of today. You're on r/cpp so you must be aware of the outrage that the NSA report stirred.

And they're not even wrong. It's not that C++ isn't safe, it's because we have solutions to problems no one is bothering to use. Don't avoid C++ and favor Rust for a lack of technology, but for the people. You just can't find people who can be bothered to write high quality code.

Your stated motto only tells me that you don't use new things because they're new - not because they're bad. You've complained, but you haven't given a credible reason to voice a complaint. There's no technical reason not to use brace initialization - none that you established. Where's the flaw? Where's the fault? What gives your grievance merit? What guideline would you suggest that isn't new = bad?

9

u/android_queen Dec 19 '23

My motto is: Use things rarely, only when needed, to express that right there the feature does something important.

I lean only slightly towards using brace initialization, but oddly, this made me want to use it more. Using things rarely sounds like a good way to make them unfamiliar and confusing. Consistency is much better for communicating your intent. What does it mean to only use something when “needed”? There are relatively few things that can only be handled on one way.

4

u/lukaasm Game/Engine/Tools Developer Dec 22 '23

It prevents more bugs for me than causes issues, and overall is net positive.

  • zero initializes structs/values

  • allows for 'custom' struct fields initialization for aggregates

  • prevents narrowing conversions

  • prevents function calls

But I am also not using initializer lists, so it won't bite me :)

2

u/NilacTheGrim Dec 23 '23

I am also not using initializer lists, so it won't bite me :)

I don't typically use it either but some types in my code rely on libs that have introduced std::initializer_list c'tors in between releases and I had at least 1 bug in my past where a new wild std::initializer_list c'tor appeared between lib versions and produced subtle bugs.

My rule of thumb is if you intend to call a c'tor on initialization (say because it's real non-trivial class type), then use ().

3

u/islandyokel Dec 20 '23

Here is some info about it in the core guidelines: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-list

It describes there where and why of the preferences

6

u/EdwinYZW Dec 19 '23

I would do: const auto tax = 0.09 * price;

-16

u/snowflake_pl Dec 19 '23

Why not static constexpr? 🙂

15

u/yu_yaki Dec 19 '23

because price might not be constexpr? Why static though?

-9

u/snowflake_pl Dec 19 '23

Maybe static doesn't make a difference for a small variable but was it large, giving it static storage ensures compile time initialization and prevents unnecessarily copying the data to stack

4

u/yu_yaki Dec 19 '23

It's still irrelevant to the specific case that you commented under. I was wondering if you had some more to say, but oh well. I do get your point though.

2

u/android_queen Dec 19 '23

Yes, but it does potentially bloat your static storage, and you don’t have enough information from this single line of code to know whether it would need to be on the stack anyway (which is not unlikely). Static isn’t one of those things that is automatically by default the better choice.

1

u/snowflake_pl Dec 19 '23

and by no means I am recomending it. Wanted to have a discussion which is exactly what happens here

1

u/android_queen Dec 19 '23

I guess it just seemed odd to me to ask “why not static” when I can see no reason why it should be.

1

u/snowflake_pl Dec 19 '23

I mean there is huge lack of context both in the original post and in my question so I understand the confusion.

3

u/_curious_george__ Dec 19 '23

Doesn’t necessarily make sense in practice.

Static storage is going to pollute the cache. Which will often be far worse than copying some trivial variable to the stack.

0

u/snowflake_pl Dec 19 '23

For optimized builds and trivial types static and automatic will be equivalent with variables completely compiled out. For bigger entities you are right, cache miss will most likely be more pricy than copy to stack. There is a threshold where copy becomes worse than cache miss but it's pretty much impossible to determine without precise measurements and even then the result will be tied to hw

2

u/Droid33 Dec 19 '23

I tried it for a while but it just makes the code very unreadable in my experience. Wish that weren't so.

2

u/gracicot Dec 20 '23

Consider yourself lucky, I advocate (and enforce) for auto const tax = double{0.09*price}. Btw, never contain money using floating point. Money is always a integer type containing pennies. You'll thank me later.

2

u/[deleted] Dec 22 '23

I quite prefer it because it looks prettier than int i=0;

I don’t know if it actually changes something about compilation or performance . It’s fun to use it!

2

u/Polyxeno Dec 19 '23

The obsession is a problem itself.

1

u/Drakonluke Dec 20 '23

Basically because Bjarne Stroustrup told us that list initialization (curly braces) is better.

Since I don't want to copy from his book by hand, I see that someone already did here:

https://stackoverflow.com/questions/18222926/what-are-the-advantages-of-list-initialization-using-curly-braces

1

u/disciplite Dec 20 '23

Look up the most vexing parse.

1

u/13steinj Dec 22 '23

There's a few general rules of thumb which end up promoting this:

  • braces for aggregates, parenthesis for classes, since constructors do work. I honestly never bought this approach. There are plenty of edge cases where your aggregate construction also does work, and aggregates can now be constructed with parenthesis.

  • assignment can do work / have a different meaning, difficult to catch initialization or assignment so better not to leave room for the question

  • parenthesis make it hard to tell if it's a function or a constructor, and sometimes this matters

  • uniform initialization is powerful and lets you do tricks on template-arg erased functions that are bound to a type without having to be overly explicit.

  • default initialization can lead to unexpected uninitialized variables

As a result of a mix of the above, I'm in the "braces over parenthesis, be explicit and use them" camp as well as the "when using assignment use uniform initialization" camp.

1

u/NilacTheGrim Dec 23 '23

I agree, I think it's totally over-used, especially for obvious stuff like PoT types or for calling c'tors... I actually prefer Foo f(bar, baz) notation for initializing via c'tor because it is symmetrical / visually the same as any other function call. Also there is no ambiguity between that and initializer lists... so there's that.

Thay being said I do like init-to-0 using {}, e.g. int i{}; as opposed to int i = 0; simply because the former is more compact.

1

u/NilacTheGrim Dec 23 '23

I agree with you. May I present this as evidence that {} for non-trivial classes is dangerous :

std::vector<char> vc {42, 'x'}; <-- tell me, what is the size of vc here? Is it 42 or 2?

If you aren't sure, then you need to stop using {} and go back to () for non-trivial class types right now.

-2

u/[deleted] Dec 19 '23

Prefer {} initialization over alternatives unless you have a strong reason not to. copy past from stackoverflow.

11

u/guepier Bioinformatican Dec 19 '23

And for completeness, copy paste from a comment under that answer, showing why the answer is problematic:

braced initialization becomes a complete mess when you have types with a ctor accepting a std::initializer_list. […] A(5,4) and A{5,4} can call completely different functions, and this is an important thing to know. It can even result in calls that seem unintuitive. Saying that you should prefer {} by default will lead to people misunderstanding what's going on. This isn't your fault, though. I personally think it's an extremely poorly thought out feature.

2

u/[deleted] Dec 19 '23

I just started learning cpp so I don't know, but learncpp also recommend to prefer brace initialization over copy and direct initialization.

2

u/guepier Bioinformatican Dec 19 '23

… And does it give reasons?

Anyway, I don’t know “learncpp” specifically, but be aware that the majority of C++ learning resources are of terrible quality according to many C++ experts. Don’t take everything you read (online or in books) at face value.

If you are looking for high-quality C++ learning resources, look at the curated list of C++ books.

6

u/ponchietto Dec 19 '23

When should I vote down?
Downvote answers that are incorrect or don't provide sufficient information to be useful in answering the question. Some answers may not attempt to answer the question at all, and should be flagged.

Copy past from stackoverflow (https://stackoverflow.com/help/privileges/vote-down).

0

u/noooit Dec 19 '23

I always avoid it unless I need to use c style designated initialiser.

0

u/ilovemaths111 somethingdifferent Dec 19 '23

are you talking about tccpp server?

0

u/DoctorNuu Dec 19 '23

sure, they also told me they are the only server I need
oh no, you tricked me

-6

u/vI--_--Iv Dec 19 '23

{} requires 4 keystrokes.

= requires 1 keystroke.

The choice is obvious.

5

u/guepier Bioinformatican Dec 19 '23 edited Dec 19 '23

Counting keystrokes is a pretty bad metric for syntax superiority, but your count is also wrong: “{}” requires three keystrokes on a US-English keyboard, as well as many (most? all?) other keyboards: Shift, {, }. (And the two adjacent keys can be typed in a much quicker succession than two arbitrary keys, and the first { and the shift key can be pressed simultaneously, so in reality typing “{}” is much faster than three average keystrokes or even faster than two average keystrokes.)

2

u/-dag- Dec 19 '23

It requires only two keystrokes in my editor.

1

u/fdwr fdwr@github 🔍 Dec 20 '23

your count is also wrong

u/vI--_--Iv left out the value in his example (unsure if intentional or oversight), {5} vs =5. Typing {5} requires 4 keystrokes for the curly braces portion because you must release Shift between braces, as you'd otherwise end up with {%}.

0

u/Particular-Case4461 Dec 19 '23

What would you consider an important use of it?

0

u/jones77 Dec 19 '23

I have like 3 tabs open with information about this I need to read. :-)

Hrm, looks like I lost a tab...