Skip to content(if available)orjump to list(if available)

Initialization in C++ is bonkers (2017)

shadowdev1

Heh, low comments on C++ posts now. A sign of the times. My two cents anyway.

I've been using C++ for a decade. Of all the warts, they all pale in comparison to the default initialization behavior. After seeing thousands of bugs, the worst have essentially been caused by cascading surprises from initialization UB from newbies. The easiest, simplest fix is simply to default initialize with a value. That's what everyone expects anyway. Use Python mentality here. Make UB initialization an EXPLICIT choice with a keyword. If you want garbage in your variable and you think that's okay for a tiny performance improvement, then you should have to say it with a keyword. Don't just leave it up to some tiny invisible visual detail no one looks at when they skim code (the missing parens). It really is that easy for the language designers. When thinking about backward compatibility... keep in mind that the old code was arguably already broken. There's not a good reason to keep letting it compile. Add a flag for --unsafe-initialization-i-cause-trouble if you really want to keep it.

C++, I still love you. We're still friends.

juliangmp

> When thinking about backward compatibility... keep in mind that the old code was arguably already broken. There's not a good reason to keep letting it compile.

Oh how I wish the C++ committee and compiler authors would adopt this way of thinking... Sadly we're dealing with an ecosystem where you have to curate your compiler options and also use clang-tidy to avoid even the simplest mistakes :/

Like its insane to me how Wconversion is not the default behavior.

motorest

> Oh how I wish the C++ committee and compiler authors would adopt this way of thinking...

I disagree. If you expect anyone to adopt your new standard revision, the very least you need to do is ensure their code won't break just by flipping s flag. You're talking about production software, many of which has decades worth of commit history, which you simply cannot spend time going through each and every single line of code of your >1M LoC codebase. That's the difference between managing production-grade infrastructure and hobbyist projects.

dwattttt

> If you expect anyone to adopt your new standard revision, the very least you need to do is ensure their code won't break just by flipping s flag.

Why would you expect that a new revision can't cause existing code to compile? It means that "new" revisions can't fix old problems, and one thing you always get more of over time is perspective.

If you don't want your code "broken", don't migrate to a new standard. That's the point of supporting old standards. Don't hobble new standards because you both want new things, but don't want old things to change.

nickysielicki

> You're talking about production software, many of which has decades worth of commit history, which you simply cannot spend time going through each and every single line of code of your >1M LoC codebase.

They can keep using the old standard.

johannes1234321

The option there is better tooling, for which the foundation exists which can do such maintenance somewhat automatically, in the simplest case by just adding the Keywords to request old behavior.

But the annoyance comes when dealing with multiple compilers and versions. Then you have to add more compatibility macros all over. Say, when being a library vendor trying to support broad range of customers.

mystified5016

Python seems to still be pretty popular despite breaking most extant code with language updates

monkeyelite

And the cost of this is that every time I open a project in another language it’s broken and I have to make changes to fix all their little breaking changes.

zahlman

>Oh how I wish the C++ committee and compiler authors would adopt this way of thinking

Many different committees, organizations etc. could benefit, IMO.

josefx

> keep in mind that the old code was arguably already broken

The code is only broken if the data is used before anything is written to it. A lot of uninitialized data is wrapped by APIs that prevent reading before something was written to it, for example the capacity of a standard vector, buffers for IO should only access bytes that where already stored in them. I have also worked with a significant number of APIs that expect a large array of POD types and then tell you how many entries they filled.

> for a tiny performance improvement

Given how Linux allocates memory pages only if they are touched and many containers intentionally grow faster then they are used? It reduces the amount of page faults and memory use significantly if only the used objects get touched at all.

riehwvfbk

You are very very unlikely to trigger Linux overcommit behavior by not initializing a member variable. It's even more unlikely for this to be a good thing.

In effect, you are assuming that your uninitialized and initialized variables straddle a page boundary. This is obviously not going to be a common occurrence. In the common case you are allocating something on the heap. That heap chunk descriptor before your block has to be written, triggering a page fault.

Besides: taking a page fault, entering the kernel, modifying the page table page (possibly merging some VMAs in the process) and exiting back to userspace is going to be A LOT slower than writing that variable.

OK you say, but what if I have a giant array of these things that spans many pages. In that case your performance and memory usage are going to be highly unpredictable (after all, initializing a single thing in a page would materialize that whole page).

OK, but vectors. They double in size, right? Well, the default allocator for vectors will actually zero-initialize the new elements. You could write a non-initializing allocator and use it for your vectors - and this is in line with "you have to say it explicitly to get dangerous behavior".

josefx

> In effect, you are assuming that your uninitialized and initialized variables straddle a page boundary

You are assuming that I am working with small data structures, don't use arrays of data, don't have large amounts of POD members, ... .

> That heap chunk descriptor before your block has to be written, triggering a page fault.

So you allocate one out of hundreds of pages? The cost is significantly less than the alternative.

> In that case your performance and memory usage are going to be highly unpredictable (after all, initializing a single thing in a page would materialize that whole page).

As opposed to initializing thousands of pages you will never use at once? Or allocating single pages when they are needed?

> Well, the default allocator for vectors will actually zero-initialize the new elements.

I reliably get garbage data after the first reserve/shrink_to_fit calls. Not sure why the first one returns all zero, I wouldn't rely on it.

motorest

> You are very very unlikely to trigger Linux overcommit behavior by not initializing a member variable.

The problem with your assumption is that you're just arguing that it's ok for code to be needlessly buggy if you believe the odds this bug is triggered are low. OP points out a known failure mode and explains how a feature eliminates it. You intentionally ignore it for no reason.

This assumption is baffling when, in the exact same thread, you see people whining about C++ for allowing memory-related bugs to exist.

fooker

> keep in mind that the old code was arguably already broken.

Reminder than compiler devs are usually paid by trillion dollar companies that make billions with 'old code'.

tails4e

Especially when doing the right/safe thing by default is at worst a minor performance hit. They could change the default to be sane and provide a backwards compatible switch to pragma to revert to the less safe version. They could, but for some reason never seem to make such positive changes

redandblack

stupid question as I have not tpuched C++ since the 90s - can the IDEs not do this with all these now almost universal linters and AI assists. Maybe something that prompts before a commit and autoprompts before/after fixes to only the inititaization. Maybe simple as a choice in the refactoring menu? Rust - where are you for proposing this fix to C++ or, is it javascript?

vrighter

that's the undefined keyword in zig. I love it. It makes UB opt-in and explicit

null

[deleted]

loeg

Compilers should add this as a non-standard extension, right? -ftrivial-auto-var-init=zero is a partial solution to a related problem, but it seems like they could just... not have UB here. It can't be that helpful for optimization.

Matheus28

Yes but it’s not portable. If zero initialization were the default and you had to opt-in with [[uninitialized]] for each declaration it’d be a lot safer. Unfortunately I don’t think that will happen any time soon.

tialaramex

You probably don't want zero initialization if you can help it.

Ideally, what you want is what Rust and many modern languages do: programs which don't explain what they wanted don't compile, so, when you forget to initialize that won't compile. A Rust programmer can write "Don't initialize this 1024 byte buffer" and get the same (absence of) code but it's a hell of a mouthful - so they won't do it by mistake.

The next best option, which is what C++ 26 will ship, is what they called "Erroneous Behaviour". Under EB it's defined as an error not to initialize something you use but it is also defined what happens so you can't have awful UB problems, typically it's something like the vendor specifies which bit pattern is written to an "unintialized" object and that's the pattern you will observe.

Why not zero? Unfortunately zero is too often a "magic" value in C and C++. It's the Unix root user, it's often an invalid or reserved state for things. So while zero may be faster in some cases, it's usually a bad choice and should be avoided.

leni536

Something like that is heading into C++26 actually. Except the initialization is not to zero, but to some unspecified value (with explicit intention of not allowing leaking garbage) and allowing to trap. It's called "erroneous values".

loeg

I don't really care if it isn't portable. I only have to work with Clang, personally.

> If zero initialization were the default and you had to opt-in with [[uninitialized]] for each declaration it’d be a lot safer.

I support that, too. Just seems harder than getting a flag into Clang or GCC.

nlehuen

Not to worry, there is a 278 page book about initialization in C++!

https://leanpub.com/cppinitbook

(I don't know whether it's good or not, I just find it fascinating that it exists)

bhk

Wow! Exhibit 1 for the prosecution.

kazinator

C++ doesn't have initiation hazing rituals, but initialization hazing rituals. (One of which is that book.)

codr7

That's what I've been saying, every line of C++ is a book waiting to be written.

nitrogen99

Well, authors are incentivized into writing long books. Having said that it obviously doesn't take away the fact that C++ init is indeed bonkers.

harry8

What would be the incentive for making this a long book? Couldn't be money.

jcelerier

It is actually. It's been shown that longer books make more sales as they are considered more trustworthy, so authors are incentivized to artificially drag them longer than they actually require

Analemma_

I imagine if I'd managed to actually memorize all of C++'s initialization rules, I'd probably have to write a book too just to get it all out, or I'd lose my sanity.

nitwit005

Imagine you're in a world where magazines are dead, but books are still a thing, and stores won't stock a thin book.

agent327

The answer to this is to replace default-init by zero-init. This removes all special cases and all surprise, at a cost that is minimal (demonstrated experimentally by its implementation in things like Windows and Chrome) or even negative. Doing so would make software safer, and more reproducible, and it would make the object model more sound by removing the strange zombie state that exists only for primitive types.

Of course we should provide a mechanism to allow large arrays to remain uninitialized, but this should be an explicit choice, rather than the default behaviour.

However, will it happen? It's arguably the easiest thing C++ could do to make software safer, but there appears to be no interest in the committee to do anything with safety other than talk about it.

shultays

  Of course we should provide a mechanism to allow large arrays to remain uninitialized, but this should be an explicit choice, rather than the default behaviour.
First you are saying "cost is minimal even negative" and then already arguing against it on the next paragraph.

ddulaney

The general cost over a several large codebases has been observed to be minimal. Yet, there are specific scenarios where the costs are real and observable. For those rare cases, an explicit opt-in to risky behavior makes sense.

shultays

  The general cost over a several large codebases has been observed to be minimal
Is this unexpected? A large code base has a lot of other things and it is normal that such changes will be a rounding error. There are lots of other bottlenecks that will just overwhelm such a such change. I don't think "it is not affecting large code bases as much", you can use that argument for pretty much anything that adds an overhead

Not to mention if you change every int a to int a=0 right now, in those code bases, a=0 part will likely to be optimized away since that value is not being (shouldn't be) used at all and likely will be overwritten in all code paths

monkeyelite

We all agree, poor defaults were chosen in C++ across the board. we have learned a lot about languages since then.

The question is what to do about it - balancing the cost of change to code and to engineers who learned it.

> but there appears to be no interest in the committee to do anything with safety other than talk about it.

There is plenty of interest in improving C++ safety. It’s a regular topic of discussion.

Part of that discussion is how it will help actual code bases that exist.

Should the committee do some breaking changes to make HN commenters happier, who don’t even use the language?

112233

There is no hope for committee. In C++33 we will probably have variables defined as

    int const<const> auto(decltype(int)) x requires(static) = {{{}}};
And when asked how on earth did this happen and why, there will be the same "we must think about the existing code, the defaults were very poor"

Meanwhile they absolutely could make sane defaults when you plonk "#pragma 2033" in the source (or something, see e.g. Baxter's Circle compiler), but where would be the fun of that.

They still use single pass compiling (and order of definitions) as the main guiding principle...

intelVISA

The root issue is that the committe has no incentive to improve the language when the current situation enriches its key members, C++ is just the vehicle they co-opted to sell books, or consulting, on solving problems that they perpetuate.

monkeyelite

I’m with you - the features they add are baffling.

> we must think about the existing code, the defaults were very poor"

What does adding bad features have to do with maintaining defaults?

agent327

I was not proposing sweeping changes to all the defaults in C++, I was proposing to adopt a single, specific change. That change does not break any existing code, removes pitfalls from the language, and has already been tried by industry and found to be beneficial. Why is it not in C++26?

https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2754r0... provides what appears to be the answer to this question: "No tools will be able to detect existing logical errors since they will become indistinguishable from intentional zero initialization. The declarations int i; and int i = 0; would have precisely the same meaning." ...yes, they would. _That's the point_. The paper has it exactly the wrong way around: currently tools cannot distinguish between logical error and intentional deferred initialization, but having explicit syntax for the latter would make the intention clear 100% of the time. Leaving a landmine in the language just because it gives you more warnings is madness. The warning wouldn't be needed to begin with, if there were no landmine.

I'm not sure what you mean with "who don't even use the language". Are you implying that only people that program professionally in C++ have any stake in reliable software?

monkeyelite

> Are you implying that only people that program professionally in C++ have any stake in reliable software?

No. I’m saying people who don’t understand C++ aren’t going to have good ideas about how to make initialization better.

And yes - comments which simply name call can be safely discard.

BlackFly

> Should the committee do some breaking changes to make HN commenters happier, who don’t even use the language?

As phrased, you clearly want the answer to this question to be no, but the irony there is that that is how you kill a language. This is simply survivor bias, like inspecting the bullet damage only on the fighter planes that survive. You should also be listening to people who don't want to use your language to understand why they don't want that, especially people that stopped using the language. Otherwise you risk becoming more and more irrelevant. It won't all be valuable evidence, but they are clearly the people that cannot live with the problems. When other languages listen, better alternatives arise.

monkeyelite

> you clearly want the answer to this question to be no

Uh yes. It’s phrased that way because it’s absurd. About half the comments in this section are a form of name calling by people who don’t understand constructors/destructors.

Those people who have no insight into how to make initialization better.

> Otherwise you risk becoming more and more irrelevant

Relevancy is relative to an audience. You want to listen to people who care and have your interests in mind.

C++ and Java are the most relevant languages in terms of professional software engineering.

BlackFly

I would say the answer is to replace both with explicit init unless you explicitly say some equivalent of "Trust me, bro," to the compiler. Some structs/data (especially RAII structs backing real resources) have no sensible default or zero.

But yeah, most structs have a good zero value so a shorthand to create that can be ergonomic over forced explicitness.

agent327

That would be a breaking change though. Having default zero-init would apply to existing source and convey it's benefits simply by recompiling, without any engineering hours being required.

gnabgib

Small discussion at the time (42 points, 6 comments) https://news.ycombinator.com/item?id=14532478

Related: Initialization in C++ is Seriously Bonkers (166 points, 2019, 126 points) https://news.ycombinator.com/item?id=18832311

ts4z

This is a specialization of the general statement that C++ is bonkers.

MichaelMoser123

and putting structure instances into an array so that you can refer to them via indexes of the array entries (as the only escape from being maimed by the borrow checker) is normal?

ts4z

C++ would be bonkers even if Rust did not exist.

MichaelMoser123

you have a point. The usual approach was to choose a subset of C++ features, so it becomes appropriate for a given project. But yes, the language is huge - as it tries to suite everyone but no one in particular (which is insane)

lblume

Unlike Rust, C++ at least has specialization...

kazinator

> This rule makes sense when you think about it

No, it is bonkers; stick to your consistent point, please.

These two should have exactly the same effect:

  bar() = default;       // inside class declaration

  bar::bar() = default;  // outside class declaration
The only difference between them should be analogous to the difference between an inline and non-inline function.

For instance, it might be that the latter one is slower than the former, because the compiler doesn't know from the class declaration that the default constructor is actually not user-defined but default. How it would work is that a non-inline definition is emitted, which dutifully performs the initialization, and that definition is actually called.

That's what non-bonkers might look like, in any case.

I.e. both examples are rewritten by the compiler into

  bar() { __default_init; }

  bar::bar() { __default_init; }
where __default_init is a fictitious place holder for the implementation's code generation strategy for doing that default initialization. It would behave the same way, other than being inlined in the one case and not in the other.

Another way that it could be non-bonkers is if default were simply not allowed outside of the class declaration.

  bar::bar() default;  // error, too late; class declared already!
Something that has no hope of working right and is easily detectable by syntax alone should be diagnosed. If default only works right when it is present at class declaration time, then ban it elsewhere.

ValtteriL

The book Beautiful C++: 30 Core Guidelines for Writing Clean, Safe, and Fast Code recommends initializing/providing default values for member variables in default member initializers intead of the initializer list used here.

""" Default member initializers define a default value at the point of declaration. If there is a member that cannot be defined in such a way, it suggests that there may be no legal mechanism by which a default constructor can be defined. """

markhahn

Most of that actually just makes sense if you approach it from the historic,low-level, minimalist direction. But maybe if you're coming from some other, higher-comfort language...

frollogaston

Coming from C, none of this made sense to me. Wut is `foo() = default;`? If you want a default value of 0, why isn't it just

  struct foo {
    int a = 0;
  };
In Python, which is higher-level ofc, I still have to do `foo = 0`, nice and clear.

Maxatar

`foo() = default;` is an explicit way to generate a default constructor for `foo`. The default constructor works by recursively calling the default constructors for all class instance fields. In C++ there are a bunch of rules about when a class has a default constructor or not, but by explicitly declaring one you are guaranteed to have it so long as all your class instance fields have default constructors.

Your example of having a field called `a` that is initialized to 0 is perfectly valid C++ as well but it's not the same as an explicitly declared default constructor.

AlienRobot

Yeah, this is obviously nonsensical.

If the constructor is "default" then why do you need to explicit set it? Yeah, I know some objects don't have constructors, but it would make more sense if you had to explicit delete the default constructor, or the keyword "trivial" was used instead of default.

motorest

> Coming from C, none of this made sense to me. Wut is `foo() = default;`?

C does not have member functions, let alone special member functions such as constructors. It's understandable that someone with a C background who never had any experience using a language besides C would struggle with this sort of info.

C++ improved upon C's developer experience by introducing the concept of special member functions. These are functions which the compiler conveniently generates for you when you write a simple class. This covers constructors (copy constructors and move constructors too). This is extremely convenient and eliminates the need for a ton of boilerplate code.

C++ is also smart enough to know when not to write something it might surprise you. Thus, if you add anything to a basic class that would violate assumptions on how to generate default implementations for any of these special member functions, C++ simply backs off and doesn't define them.

Now, just because you prevented C++ from automatically defining your constructors, that does not mean you don't want them without having to add your boilerplate code. Thus, C++ allows developers to define these special member functions using default implementations. That's what the default keyword is used for.

Now, to me this sort of complaining just sounds like nitpicking. The whole purpose of special member functions and default implementations is to help developers avoid writing boilerplate code to have basic implementations of member functions you probably need anyway. For basic, predictable cases, C++ steps in and helps you out. If you prevent C++ from stepping in, it won't. Is this hard to understand?

More baffling, you do not have to deal with these scenarios if you just declare and define the special member functions you actually want. This was exactly how this feature was designed to work. Is this too hard to follow or understand?

I think the problem with C++ is that some people who are clearly talking out of ignorance feel the need to fabricate arguments about problems you will experience if you a) don't know what you are doing at all and aren't even interested in learning, b) you want to go way out of your way to nitpick about a tool you don't even use. Here we are, complaining about a keyword. If we go through the comments, most of the people doing the bulk of the whining don't even know what it means or how it's used. They seem to be invested in complaining about things they never learned about. Wild.

frollogaston

Yes it's too hard to follow or understand. Of all the langs I've used, C++ is the only one I can't trust to default-init things the expected way, and I use it every day.

zabzonk

> If you want a default value of 0, why isn't it ...

It is.

frollogaston

I know that works too, but there are also other unclear ways to do it.

codr7

I agree in the example given.

But add templates to the mix and a generic default becomes quite useful.

112233

how does

    int x = x;
has ever made sense? In hostoric minimalist direction?

(and if you have to ask, x is initialized — with the uninitialized value of x)

int_19h

It is very occasionally useful when you need to define a self-referential data structure, i.e. something like:

  struct foo { foo& p; ... };
  
  foo x{x, ...};
Still, this is hardly a good justification for it to be the default behavior. There's a reason why ML has `let rec`.

112233

Thank you for this, it illustrates an important distinction. (Your example would be clearer if you used a pointer instead of a reference)

Address of variable does not depend on it's value, and can be known and used before the variable is defined. At no point in your example value of "x" is used before the end of initialization.

However, in order to allow that, the language goes and allows the use of uninitialized value too. That is just plain horrible design.

e-dant

Let the language die, hope it goes quicker than cobol.

trealira

C++ is not going anywhere. It's even still used in gamedev to make new games. It's used in HPC and scientific computing. Windows applications often use it. And so on.

compiler-guy

https://www.phoronix.com/news/GCC-15-Merges-COBOL

COBOL Language Frontend Merged For GCC 15 Compiler Written by Michael Larabel in GNU on 11 March 2025 at 06:22 AM EDT. 33 Comments

jandrewrogers

For better or worse, modern C++ is still the most capable and expressive systems language. To replace it, we need (at a minimum) a language with similar capability and expressiveness in the low-level systems domain. The options are really thin; Zig probably comes the closest but it is a bit austere coming from recent C++ versions.

I think we can do significantly better than C++ as a systems language. We just haven’t landed on a language that really nails the design.

johnnyjeans

> For better or worse, modern C++ is still the most capable and expressive systems language.

Not really. Rust, ATS, D, and some implementations of Lisp and even Haskell if you slay the dragon of actually learning GHC. Modern C++ is honestly overrated in my opinion as an extensive user of the language with 300k lines in a modern dialect alone. It's a pain in the ass to step through in a visual debugger and core dumps may as well be useless no matter the platform. It's extremely grating to read and to write. Compilers have a tendency to crash like crazy if you get too cute. There's still no compile-time (or runtime) reflection. I would literally rather be writing proofs for a dependent type system than deal with heavy template metaprogramming.

jandrewrogers

C++20 metaprogramming is pretty clean and straightforward. It became usable around C++17, though the learning curve is a bit steep. I can’t remember the last time I saw a compiler crash, and I’ve used many compilers on code bases that use a lot of dark corners of C++. The occasional compiler bug is a thing though.

I didn’t say C++ was amazing, just that recent dialects are better than the alternatives in practice, many of which I have also used for similar code.

Rust is not a substitute for C++ unless your code isn’t all that low-level, it lives closer to the abstraction level of Java. There are a number of odd gaps in the Rust feature set for low-level systems programming (database kernels in my case), the rigid ownership/lifetime model doesn’t play nicely with fairly standard systems-y things like DMA, and the code is always runs slower for some inexplicable reason.

I’d love something to replace C++ but to be a candidate it can’t be less expressive, slower, and so rigid that it is difficult to do some ordinary systems-y things. A nerfed programming language is not the answer to this question.

bdangubic

“quicker than cobol” means it will die in the next 100 years (maybe) :)

greesil

I don't think it's going anywhere, too much existing code that's still useful. People STILL use Fortran 77 for goodness sake.

lblume

Fortran may still be used but is considered functionally dead nonetheless. Nobody is hiring Fortran devs anymore (and those who do put themselves in a really hard market position). Yet, learning C++ might still be a more valuable skill than learning Rust.

pjmlp

Yet, Fortran 2023 is the latest standard, and Fortran support is one of the reasons why CUDA won over OpenCL.

kergonath

Fortran 77 is dead. Fortran is not, and yes, people still get hired to use it. Just maybe not in your field.

gosub100

COBOL is alive and well. Why would a company rewrite a codebase that has decades of error free functionality? What do they get?

cheema33

> Why would a company rewrite a codebase that has decades of error free functionality? What do they get?

All well and good if it is something you do not have to modify/maintain on a regular basis. But, if you do, then the ROI on replacing it might be high, depending on how much pain it is to keep maintaining it.

We have an old web app written in asp.net web forms. It mostly works. But we have to maintain it and add functionality to it. And that is where the pain is. We've been doing it for a few years but the amount of pain it is to work on it is quite high. So we are slowly replacing it. One page at a time.

gosub100

the insurance companies running COBOL don't care. it's cheaper to pay a cowboy $X00,000/yr to keep the gravy dispenser running than trying to modify it. by definition, this is code that's been in use for decades. Why change it?

pjmlp

First someone needs to rewrite famous open source compiler development tools like GCC and LLVM into something else.

indigoabstract

I think this saying applies here pretty well: Horses don't die when the dogs want them to.

monkeyelite

Initialization does look insane. But as with most C++ complexity this is inherent.

Lists of the “good parts” of C++ over C usually include RAII. But f we imagine starting with C and adding C++ features to see when complexity explodes. I think the worst offender is constructor/destructor.

They require the language to perfectly track the lifetime of each member of every structure. If you resize a vector, every entry must call a constructor. If exceptions are possible, but insert little cleanup calls into all possible code paths.

Want to make a copy of something? Who is responsible for calling constructor/destructor. Want to make a struct? What if one member requires construction? How do you handle a union?

The result is micromanaging and turning most operations into O(n) init/cleanup calls.

The modern C approach avoids all of this and allows you to manage pieces of memory - rather than values. Zero initialize or leave uninitialized.

So what do we lose? Well classes own resources. If you have a vector<MyObject> and MyObject has a member vector<Items> then we should be able to cleanup without looking inside each member of each element.

I think we should separate resource allocation from use. Allocators are the things that care about cleanup, move, etc. This should be the exception - rather than the default way to think about structs.

AlienRobot

I'm not very good with C++, so one time I tried to use RAII to do all sorts of neat GUI things, like freeze property events and ref count uses of files to know when to freed them from memory.

Essentially instead of doing

    object.freeze();
    object.setProperties(...);
    object.thaw();
I tried to do

    {
        Freezer freezer(object);
        object.setProperties(...);
    }
EVERY time I need a start/end matching function I used RAII instead because it looked neat. I tried to make "with" from Python in C++.

The problem is that exceptions thrown in a destructor can't be caught, which made this coding style practically impossible to use. Thawing the properties meant dispatching property change events, which meant that event handlers all around the app would be executed inside a destructor unaware that they were being executed inside a destructor. If any of these threw an exception, the whole thing crashed. In hindsight dispatching these events from a setter instead of from the main event loop also creates all sorts of trouble.

int_19h

The closest equivalent to `with` from Python would be a higher-order function defined such that it can accept a lambda (i.e. it needs to be a template). Then you'd write something like:

   object.batchEvents([&]{
     object.setProperties(...);
   });
(for bonus points, pass object reference as argument to the lambda)

gpderetta

> Want to make a copy of something? Who is responsible for calling constructor/destructor.

What do you mean? The compiler will do it for you.

> This should be the exception - rather than the default way to think about structs.

the way that RAII in C++ recursively construct and destroys arbitrary object graphs is extremely powerful. It is something that very few other languages have (Rust, any other?). It should definitely be the default.

> I think we should separate resource allocation from use. Allocators are the things that care about cleanup, move, etc.

I'm not sure what you mean by use. If you mean we should separate allocation from construction, I agree! But then so does C++. They are tied by default, but it is easy to separate them if you need it.

monkeyelite

> What do you mean? The compiler will do it for you.

It will. And the only cost to you is you have to understand initializer lists, pod types, copy constructors, move constructors, launder, trivially_destructible, default initialization, uninitialized_storage, etc.

> the way that RAII in C++ recursively construct and destroys arbitrary object graphs is extremely powerful

And extremely complex.

The big fallacy here is that you would want to manage resources at the individual node level - rather than for a batch.

> I'm not sure what you mean by use

It’s similar to the idea of arenas (also made difficult by constructors btw). You can make sophisticated systems for managing allocations of individual nodes in a graph - like reference counted smart pointers. Or you can avoid the problem entirely by deallocating the whole group at once.

Imagine if C++ structs were required to be pod and classes were not. Then you could always know that a struct can be trivially allocated/deallocated etc.

Then you could design data structures for pod types only that didn’t have to worry about O(n) cleanup and init.

bluGill

There is often value in putting a class in a struct. Your proposed rule of struct is POD means there will be many less structs, and force people to think about POD or not when the vast majority of the time that doesn't matter to them.

gpderetta

> Imagine if C++ structs were required to be pod and classes were not. Then you could always know that a struct can be trivially allocated/deallocated etc.

static_assert(is_trivial_v<T>)

rnikander

Been trying Rust for some months now. The IDE experience is so much nicer I'm probably sticking with it, but the restrictions on how I write code are still grating on me. I need to learn the language better, but now I still feel like I wanted something more like C++ 2.0 without as much paradigm shift.