Hacker News new | past | comments | ask | show | jobs | submit login
C++23: std:out_ptr and std:inout_ptr (sandordargo.com)
73 points by ingve on Dec 9, 2022 | hide | past | favorite | 81 comments



I'm not sure how these are supposed to be helpful. You often won't know if a C API has deleted a pointer until you actually examine its return value. So instead of

  if (foo(p.release()) == 0) { ... }
you generally need to do

  if (foo(p.get()) == 0) { p.release(); ... }
Instead of reducing bugs, these might be introducing new footguns.


Your C API here takes a `T*` but I think that the intended use for these new functions is with C APIs that take `T**`. Those are somewhat inconvenient to make interoperate with smart pointers. For example, in C you might have something like this:

    void c_api_that_returns_via_an_out_parameter(T** ret) {
        *ret = new T();
    }

    T* p;
    c_api_that_returns_via_an_out_parameter(&p);
Then you might try to change this to use a smart pointer as:

    std::unique_ptr<T> p;
    c_api_that_returns_via_an_out_parameter(&p);
But this won't compile because you can't take the address of a `std::unique_ptr<T>` and then pass it where a `T**` is expected. So instead you need to do something like this:

    T* tmp = 0;
    c_api_that_returns_via_an_out_parameter(&tmp);
    std::unique_ptr<T> p(tmp);
    
That can be a bit of a pain. These new functions serve as adapters to make this easier. They take in a `std::unique_ptr<T>` and provide a `T*` that you can pass to the C API:

    std::unique_ptr<T> p;
    c_api_that_returns_via_an_out_parameter(std::out_ptr(p));
No temporary needed.

If your C API only ever passes and returns `T*` and never uses `T**` then I think that you don't need these new functions and you can continue to do things the current way. For instance, if you have a C API that allocates a new object and then returns a pointer to it then you can take this return value and immediately store it into your smart pointer:

    std::unique_ptr<T> p(c_api_that_returns_a_pointer());
And if you have a C API that takes a `T**` and then deallocates it:

    c_api_that_deallocates(p.release());
Although really your smart pointer should be doing this for you so you'd never need to do it explicitly. If you're ever manually calling `.release()` then that indicates a place where the smart pointer abstraction has broken down. You want to minimize or eliminate that. Note that in the examples using the new functions there are no explicit calls to `.release()` anywhere and this is a good thing.

I can't recall ever seeing a C API that conditionally deallocates the pointer passed in. Do you have an example? Most C APIs that I'm familiar with have one function that allocates a new object and a separate function that unconditionally deallocates it, acting analogously to `malloc` and `free`.


> If you're ever manually calling `.release()` then that indicates a place where the smart pointer abstraction has broken down. You want to minimize or eliminate that.

Yes, that's life when you're at the boundary with a C API.

> I can't recall ever seeing a C API that conditionally deallocates the pointer passed in. Do you have an example?

realloc()?

Generally when you have an in-out parameter, it's doing more than just releasing resources, so there's a potential for failure. And in the failure case, the caller will often retain ownership of any pointers it passed. In fact, off the top of my head, I can only think of one function that is contrary to this, and that is DeferWindowPos() in Windows, which invalidates the input handle even on failure.


> realloc()?

OK, I'll give you that one, but that's a rather unusual case. It has complicated semantics. It is unlikely to interoperate well with any smart pointer without careful, manual work.

It doesn't take a `T**` so it doesn't seem relevant to discussions of std::out_ptr though? You won't be able to use std::out_ptr with realloc so there's no chance of making a mistake with it.

> Generally when you have an in-out parameter, it's doing more than just releasing resources

I'm still confused. What function do you have that is both releasing resources and also doing other work which might fail? Even something like `fclose` which needs to flush buffers and then release resources will always release the resources, even if the flush fails.

I'm more familiar with APIs that have:

- One (or more) functions to explicitly allocate the object

- Many functions that do work with that object and that might fail but that will never deallocate the object

- One function to explicitly deallocate the object

For example, SQLite has sqlite3_open to create a new database object, sqlite3_prepare, sqlite3_exec, etc. to operate on the database object, and sqlite3_close to deallocate the database object.


> It doesn't take a `T**` so it doesn't seem relevant to discussions of std::out_ptr though? You won't be able to use std::out_ptr with realloc so there's no chance of making a mistake with it. [...]

The problem is the same, it just happens to not take a T**. The problem is the same for any function that takes T**, I just couldn't think of one off the top of my head. I listed some below now. But also note that the absence of many APIs taking T** would also be an argument for these smart pointers not being so useful, so it's not really a counterargument!

> What function do you have that is both releasing resources and also doing other work which might fail?

See for example getdelim() or even asprintf(). asprintf() isn't guaranteed to return a valid pointer due to an error, so you can't free it unconditionally. getdelim() also isn't guaranteed to free the input if there is an I/O error, so you can't release that unconditionally either.

It would be helpful if you try to list some functions you believe you can use std::inout_ptr on.


I'm not sure what issue you're seeing with getdelim(). It never releases the underlying memory, AFAICT. You always need to call free at the end of the loop, regardless of whether there was a read error, a realloc failure, you hit EOF, or you broke out of the loop early. So why wouldn't the following be OK?

    std::unique_ptr<char, free_deleter> line;
    size_t len = 0;
    while ((read = getdelim(std::inout_ptr(line), &len, delim, fp)) != -1) {
        // ...
    }
If the getdelim call ends up calling realloc and succeeding then we want to forget about the old pointer and not call `free` on it. We want to remember the new pointer and call `free` on that when we're done with the loop. That's what std::inout_ptr gets for us. It calls release() before the getdelim call and then calls reset() with the new value after the getdelim call.

If there is an I/O error or a realloc failure at some point in the file then `line` is left unmodified, pointing to the existing buffer. We still need to free that so keeping it under the control of the smart pointer is the right thing to do.

This seems like a perfect fit for std::inout_ptr.

The situation asprintf() is unfortunate. If it had been designed to set the out parameter to NULL on error or just to guarantee that it was unmodified on error then it would work with std::out_ptr. Unfortunately they decided that the out pointer would be instead be undefined on error so it is not safe to use with std::out_ptr.


> Instead of reducing bugs, these might be introducing new footguns.

Same thing could be/has been said about std::string_view or std::span but here we are.

Like you said, a bare pointer could mean anything. This at least standardizes this particular footgun in question (which means one less reason to expose bare pointers in your API) so we are supposed to pay extra attention when we see one of those, I guess?


> Same thing could be/has been said about std::string_view or std::span but here we are.

It's the first time I'm hearing this, and it doesn't sound like an opinion I've ever had. Those are just range-checked pointers; their ownership semantics aren't any different from those of raw pointers, and they're no less safe than raw pointers. In contrast these actually do have weird ownership semantics, and they have a propensity to introduce safety bugs into the common use cases that didn't exist before.


When I see a raw pointer in C or C++ code I know automatically that gotchas are involved and I need to be extra careful.

When I see std::string_view, nothing tells me that this may lead to memory corruption because the underlying storage may go away at any time (and the compiler will happily let this happen). New C++ features simply should not create new memory corruption footguns in addition to the existing ones, embarrassments like iterator invalidation are already bad enough (and worse than typical C memory management issues, because in C such issues are usually 'in your face', while C++ hides them beneath layers upon layers of stdlib abstractions).


> When I see std::string_view, nothing tells me that this may lead to memory corruption because the underlying storage may go away at any time

That's not true. The word "view" quite explicitly tells you that it's a view... into something else, whose existence is generally independent of you (just like in real life!). If anything, it's clearer than an asterisk.

> (and the compiler will happily let this happen).

Just like with pointers and iterators. There's no difference here.

> When I see a raw pointer in C or C++ code I know automatically that gotchas are involved and I need to be extra careful.

You "know" this for iterators too. There's no reason why you can't "know" it for views too. It's not like they're introducing a new ownership concept here - these are just bounded versions of iterators and pointers.


> It's the first time I'm hearing this

Say that you have some `Person` class with a `get_name()` method that returns the person's name. Then maybe you write some code like this to use it:

    Person person;
    // ...
    std::string_view name(person.get_name());
    // Use `name` here
Is this code safe? Well it depends on the implementation of `Person::get_name`. Maybe it looks like this:

    std::string& Person::get_name() {
        return m_name;
    }
Then the code should be OK because the call will return a reference to a member of `person` and `person` will outlive `name`.

But what if instead the implementation looks like this:

    std::string Person::get_name() {
        return m_first_name + " " + m_last_name;
    }
Now you're in trouble. A temporary string will be created and the string_view will refer to that string. That temporary gets destroyed at the end of the statement and then `name` is dangling. By the time you get to use `name` it is already broken.

It is very easy to make this kind of mistake. Much easier than with pointers IMO since you usually have to explicitly take a pointer to something and you can't directly get a pointer to a temporary (`std::string* p = &person.get_name()` is an error if `Person::get_name` returns `std::string`).

By contrast, getting a const reference to a temporary and then constructing a string_view out of it is not an error or even a warning. It is all done implicitly so there is no indication in the code that it is even happening. The only difference between code that is correct and code that is incorrect is a single ampersand far away in some header file.

This type of mistake probably won't get caught in code review. How often does a person really go track down and examine a header file when reviewing a pull request? Probably they're only going to look at the actual files that are being changed.

Even worse, say that `Person::get_name` is using the first implementation so the code is correct and working. But later on somebody does a refactor such `Person::get_name` uses the second implementation. Now they've broken things but they're unaware of this fact. They want to be responsible and find any problems that they might have introduced. The first step is to run a build and see if there are any complaints from the compiler. That is successful and the compiler produces no warnings.

Encouraged by this they then run all the tests. And all the tests pass! Reading memory just after it has been freed will often give you back the last thing that was stored there so the tests see the values that they expect. So with a successful build, a successful run of all the tests, and no problems spotted in code review, they confidently merge the change. And now you've got a use-after-free in your code that will eventually cause a problem.

Yes, using Address Sanitizer will catch this. But it is still a pretty easy way to introduce a bug into your program. Code that does not look at all suspicious can be completely broken.


The root cause of the danger you illustrate here IMO is actually a fault in the way the `std::string` to `std::string_view` implicit conversion is designed, as opposed to something inherently wrong with the concept of view/span classes.

In my opinion, `string_view` and `span` are otherwise wonderfully much-needed concepts (that arguably should have been built into the language itself, like Rust slices) that should never have been designed to allow implicitly creating views of temporaries. Disabling implicit conversion/construction from rvalue references is quite possible in C++17 and beyond, and very effectively prevents accidentally implicitly viewing temporaries just fine (I’ve done this myself in some enhanced span-like classes I’ve written), so I’m really not sure why string_view was designed this way.

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


I think that would be safer. But then it would presumably disallow things like:

    void frob(std::string_view sv);
    std::string a = "a";
    std::string b = "b";
    frob(a + b);
This is allowed today and does not have any problems that I'm aware of. You could work around this by changing the call to:

    frob(std::string_view(a + b));
But that feels cumbersome. I think the goal of std::string_view was to be useful as a parameter for a function so that you could pass in anything remotely string-like and it would implicitly convert and do what you meant. Requiring explicit conversions at the call sites would go against that goal.

Another thing that was desired was the ability to take an existing function that takes a `const std::string&` and change it to instead take a `std::string_view` and not have to update any of the callers. If some callers that worked with the old function are going to need an update to work with the new function then it gets a lot harder to change the function. Or maybe impossible if you don't control all of the callers.

I don't see how you can get both the ease-of-use and the safety short of reinventing something like Rust's lifetimes.


I certainly don’t disagree with you there (about ease-of-use vs safety). I personally believe the “right” choice in C++ is to err on the side of safety (at least when adding new stuff), and wish STL did too — especially given how notoriously difficult it is to write C++ code that isn’t plagued with memory corruption bugs

I know anything other than switching to Rust is a losing battle of compromises in some sense, but many of us working with huge codebases written in C++ don’t have the luxury of that choice being unavailable.


If you write C++ code plagued of memory bugs maybe it is bc you take it too far. I fo not think it is particularly hard to write memory safe code.

Sure you mist avoid a few things but there are alternatives on what to do instead/not what to do.


Ok, so downvote and no reply:

- you can use string_view more conservatively

- you can stick to value semantics.

- use spans in things that do not escape.

- use smart pointers.

- do not capture escaping lambdas that have capture by reference.

If you go wild raw pointers willy-nilly around, then yes, you are gonna have a plague of sh*t because you are an incompetent using C++. I do not expect people to play the violin or drive a car without a minimal of training.


I'm guessing that the downvotes were because people were focusing on how easy c++ makes it to unwittingly introduce such bugs.

So suggesting a disciplined usage of c++ sounded like a hard sell. It's helpful that you elaborated on the details.


It is not so much of a disciplined thing compared to what you need to do in C...


This is to allow foo(temporary_string) where foo takes std::string_view.

The real problem is that in C++ temporaries are destructed at the end of the expression, not at the end of the block that contains them. With the latter rule the example and many other cases will be safe.


I would flag assigning a return value to a string_view in code review. Same as assigning to a pointer.

Yes, it’s one more thing nudging the programmer toward unsafe use, but this is C++ we’re talking about: only the strong survive.


And the way lambdas are implemented, that can be type-erased into function<> with no regard to capture-by-reference.

C++ is a huge sinking ship...


Yay more stuff to think about, while not having any seeming benefits ? I really wish some committee would just figure out a C++ for the 2020s kind of, "One way fits most" solution that removes most of the legacy features from the language (like maybe just warning if you are about to use legacy features or just preventing you to use some obscure way to iterate containers for example that was superseded already in 2011 by C++11 for example.

Is there anything like this in the plans ?


P2687, P2657 are two attempts in the early stages.

The basic idea is you mark a file as not allowed to use some old feature, and then the code throws an error if you use one. C++11-20 were mostly about finding and adding all the little details that you actually need to write code without the bad old stuff.

C++ believes that the key to their success is backward compatibility. Even though you shouldn't use a lot of old stuff in new code, there is a lot of old C++ code out there that it isn't worth rewriting in a different language, so they cannot drop support for the old superseded stuff even though you shouldn't use it.

Clazy and cppcheck will warn about using some old constructs when there is a new/modern way that is better. However most changes of the type you want require a large redesign to implement, and if the code hasn't been touched in years that isn't going to happen.


Carbon or CppFront is what you're looking for.

C++ itself won't ever remove legacy just like other languages never really remove legacy. Nobody wants to be the next Python3.


Idk python3 seems to be doing pretty well


It took 14 years to go from Python 3 being released to Python 2.7 finally being officially sunset. A date that was pushed back multiple years because there was such a strong python 2 holdout.

And Python 3 is the success story here. You could instead easily end up being Perl 6 instead.


I see your point, and I don't even disagree with it really. I don't know the history of python and why they needed to make all of the changes at once, rather than gradually deprecating features and then eventually removing them.

I will reiterate my point from a sibling comment: always adding layers but never removing anything is going to get incredibly complex. The complexity will only ever grow. That complexity is a cost and a risk just as much as alienating a large part of your community is.

Imagine the miles and miles of detritus that will be in the C++2122 if nothing has ever been removed in the name of backwards compatibility.


The web hasn't removed anything and it's still going strong despite dozens if not hundreds of deprecated features.

Windows has barely removed things and similarly is going strong.

Backwards compatibility is an extremely powerful and desirable feature. There's other ways to keep the working set of complexity in check without losing compatibility (eg linters, modernizers, or profiles)


A) "The web" is not some unified thing so having a certain web technology come and go is categorically different than a language deprecating features.

B) I wouldn't exactly hold up "the web" and Windows as shining examples of things are going great. Even just using Windows you can see the complexity escaping control, for example there's 3 separate ways in which to change volume for sound devices on windows. Each one with a different UI and found in a different place. To say nothing of attempting to develop on it. As for the web, companies like Mighty[0], whose whole shtick is "the web and the browser you need are too bloated and slow in order to run on your actual machine. The obvious solution is to add another layer and run that browser in a virtual server and pipe the screen back to you", are getting backed and people see as a "solution". This is madness.

C) > There's other ways to keep the working set of complexity in check without losing compatibility (eg linters, modernizers, or profiles)

That's a "solution" only in so far as you don't consider all of those things are yet another layer of complexity that we're adding on.

[0]: https://www.mightyapp.com


Guido van Rossum mentions the break between python2 and python3 a bit in the recent Lex Fridman, you might be interested in this.

Many companies and many of us put in hundreds to thousands of hours moving from 2 to 3.


And I agree that this was a real cost. Yet despite that, one time, cost, enough companies chose to update the code rather than migrate. And the language is now a very popular choice.

I personally think that never removing legacy aspect of a language is a clear recipe for insane complexity.


I think the lots of changes that is having c++ in every release is killing the language.


Say those stuck in Java 8, C# 7, Python 2, C89, Ada83, Fortran77,....

It is a pain, but languages are software products as well, so they either get new features to keep going on each new release or they wither and fade away.

Eventually some do still die of complexity, replaced by simpler languages, and the cycle reboots, see PL/I, Algol 60/68, ...


> or they wither and fade away

C and assembly enter the chat


> C and assembly enter the chat

Wouldn't you agree that the fraction of software written in C or asm has shrunk tremendously over the last decades?


C is continuously gaining features as well (even if it didn't, it's entrenched as the low-level implementation language of all major operating systems, so it's an exception to the rule). Assembly is evolving at least at the speed of your target chip family.


C23 and AVX512 greet them.


I wonder what the ratio of intrinsics to raw assembly is


Those using VC++ for ARM or amd64 only have intrisics to chose from, unless they make use of MASM (or similar), as it only supports inline Assembly in x86 mode.

Burroughs (now Unisys ClearPath MCP) showed that intrisics are enough, no need for raw Assembly, so in a sense it isn't as crazy idea, and much developer friendly than the inline syntax used by GCC and clang.


Which assembler syntax for which target and is it actually human writable or does it need a proprietary tool chain?

ISAs have to exist but the way that code is generated for them is as varied as the landscape of high level languages.


It is really hard to keep up.

I often have to Google for definition when I read code. Inevitably someone uses the latest feature.


My feeling is that it's the amount of characters written.

Used to be foo* x=new foo(). Now it's std::shared_ptr<foo> x=std::make_shared<foo>()

It adds up, every line of code is three times longer than it used to be.


While I agree C++ is very verbose, I would argue that modern C++ reduces the amount of code you need to write. The full code above should be : foo* x = new foo(); if (x != nullptr) { ... } delete x;

and the equivalent modern C++: auto x = std::make_shared<x>(); ...


> Used to be foo* x=new foo(). Now it's std::shared_ptr<foo> x=std::make_shared<foo>()

There's `auto` for that reason. No need to duplicate the info.

And: In general code is read more often than written, and the variant with `make_shared` provides extra information on the purpose of the heap allocation. That first line with the raw pointer and new requires following all calls closely to understand the intention. (Aside from also handling the lifecycle, which would this be code which one would have to write elsewhere, your example is missing at least one `delete x` (and likely more handling, considering this being a shared, not unique, ptr)


I started using std::shared_ptr in every project in 2008. Isn’t it late to denounce the changes now? The state of most C++ codebases is infinitely better today compared to then, partly owed to the added descriptivity.


I don’t think it’s killing it, but it’s definitely a pain in the ass. Not sure what major malfunction our industry is suffering from, but we seem to have settled on continuously running just to keep in the same place.

Apps, operating systems, cars, languages, everything is being updated all the time.


I would say that calling these "C APIs" is a bit misleading, as they have to call `new` for these helper types to be useful. I would call these legacy C++ APIs, although I have recently seen new APIs written with this horribly awful `void foo(T* out_param_for_owning_ptr)` interface.

Interfacing with these with a smart pointer without a helper type is kind of inconvenient, since then you need to do something like:

  T* raw_owning_ptr;
  foo(&raw_owning_ptr);
  std::unique_ptr<T> ptr(raw_owning_ptr);
`out_ptr` and friends are a bit niche, just for interfacing with these kinds of APIs.


Why would you have to call `new`? Why would `malloc()` not work here?


It would; you'd just have to supply a custom "free_deleter" in the definition of the unique_ptr that calls free instead of delete. I've used this for Windows System calls like GetAddrInfoExW which requires calling FreeAddrInfoEx when you're done.

    std::unique_ptr<ADDRINFOEXW, addrinfo_deleter> holder;
    ADDRINFOEXW hint = { .ai_family = AF_UNSPEC };
    if (const auto result = GetAddrInfoExW(
        sHost
        , nullptr
        , NS_ALL
        , nullptr
        , &hint
        , std::out_ptr(holder)
        , nullptr
        , nullptr
        , nullptr
        , nullptr); result != ERROR_SUCCESS) {
        // print error here
    }


This seems reasonable for working with C APIs.


Or globally replace the new and delete operators to call malloc & free, as they commonly already do such as in libstd++ and libc++

But having malloc/free cross a library boundary (that is library A malloc and wants the caller in a different library to call free) is also a code smell in general and potentially very problematic. So you'll be generally doing custom deleters regardless


Ah, right, so `out_ptr` works with any unique_ptr and shared_ptr, doesn't have to hold the `default_deleter`. `default_deleter` would call `delete` down the line, which does not match up with `malloc`.


Correct, the main value of std::out_ptr is the exception safety. There is no gap between the call and when you wrap the value in a smart pointer where something can happen and cause a leak. Is it strictly necessary in all cases? No, but it's a nice to have because it makes code less error prone if there are multiple paths. You can ensure the resource will be released when the scope ends. A code reviewer could look at the deleter to ensure it was the correct one for the use and be satisfied in most cases.


Problem with C++ is that it's easy to add stuff, and super hard to get it out of the language again. Inevitably leads to bloat and an accumulation of wrong decisions.


Arguably a lot of newer additions are there as an alternative to past bad decisions, and things do get deprecated and removed now and then.


You’re obviously wrong, it’s very hard to add stuff. Both technically and from an ISO perspective.


Still a lot simpler than removing something.


C++ is not much larger than any other language. It doesn't fit together as nice as others, but it isn't really much larger either. Unless your code is trivial, you will be working with a project that is much larger than all of C++.

That last is also why no language can afford to get rid of anything (see python 3 which took over a decade to catch on), someone is using the old thing in code they don't want to touch.


I have to work with C++ professionally one and off based on client requirements is there an _efficient_ resource that would allow me to keep up with all that has happened beyond C++14?

At the rate the committee adds stuff it feels like it is a full time job just to keep up.

Also is there any initiative within C++ to do a subset dialect with bowling alley guard rails? Something analog to the old C++ JFS standard, or something analog to dlang '-betterC' dialect flag?


Not sure if it's really what you are looking for, but the C++ Core Guidelines (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) are what I check when I have to touch a C++ code-base. It precise which parts of C++ are to be used and which are to be avoided according the creators.


cppreference[1] is fairly minimalist, usually up to date and clearly marks which feature came with which standard. It is generally useful for everyday c++ coding.

[1] https://en.cppreference.com/


Full disclosure: I don't work with C++ anymore.

You don't have to keep up with all the stuff it adds. If you actually need a certain thing C++ has added -- that you're unaware of -- you'll naturally find it when you go looking for it.

Otherwise, it's best to just stick with the feature-set that you know. KISS/YAGNI/if it ain't broke, don't fix it (but if it is broke, find a better way). Et other cliches.


I strongly disagree with this. While you can keep using the old stuff, many of the new things will make your code better if you use them. Sure you don't need the new stuff, but the highlights are important. There are also a lot of esoteric things that only a few people will use (but they really need), but you need to keep up just so you can use new features that make your code better.


This repo has a concise summary of new features, if that is the sort of thing you are looking for: https://github.com/AnthonyCalandra/modern-cpp-features


The construction of the opening paragraph is awkward and I think probably outright wrong?

> This week, let’s continue exploring the new world of C++23. We are going to discuss two new standard library functions and their outputs (std::out_ptr, std::inout_ptr), two new standard library types (std::out_ptr_t, std::inout_ptr_t).

IMNSHO the two lists in parentheses should each be next to the thing referring to them, like this:

This week, let’s continue exploring the new world of C++23. We are going to discuss two new standard library functions (std::out_ptr, std::inout_ptr) and their outputs, two new standard library types (std::out_ptr_t, std::inout_ptr_t).


a similar concept came up here

https://www.youtube.com/watch?v=ELeZAKCN4tY


The difference is that Cpp2's in/out references are actually useful. With them, it would be feasible to completely ban uninitialized variables.

BTW, P2723[1] tries to solve the same problem by zero-initializing everything by default. I'm not a fan of it. It's less elegant, it incurs potential performance cost and zero isn't always the right default.

[1] - https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p27...


I don't understand that proposal. Compilers can already add (and already have added) a flag to auto-initialize variables (-ftrivial-auto-var-init?) if they want to... so why isn't that the end of the story? It's one thing to say "all variables must be auto-initialized" (which can doesn't need this proposal, as compilers can already do it), and I can understand that. But it's another thing entirely to say "programs should be able to depend on the auto-initialized value", which is what this proposal seems to be actually asking for. That's asking for an explicit language feature to be made implicit, and it's orthogonal to the security issue it's claiming to address. Why?


Because it isn't part of the language official semantics, and is compiler specific.


The spec could just say "compilers must provide an external mechanism to initialize all variables automatically" without actually letting all programs depend on this feature being enabled. If security is the problem, letting people control this at the compiler level seems like the solution. Not forcing a semantic change on all program authors.


It seems to be at least supported by gcc and clang, I am not sure about Microsofts compiler, however I thought clang could produce compatible binaries?

This seems to be a non issue?


There are more than 3 compilers out there....


For C++? Approximately following the standard evolving? Can't think of a fourth still surviving


Intel, PGI, ....

As for the rest, what matters is what the OS vendors puts on the SDK for the CPU one needs to write an application for, and there is a world out there besides mainstream desktop OSes and mobile phones.


While herb did a talk about `in` and `out` parameters, it is very different than this concept.


Its better to migrate to rust. Instead of copying & implementing these things from other languages.


I agree that ideally everything should be written in safer alternatives, in most scenarios is not feasible to migrate from C++ to another language, because of the code base size.

I think cppfront[0] is the way to go if you want to write a safer language on top of C++, you can watch the talk about it here[1].

[0] https://github.com/hsutter/cppfront [1] https://www.youtube.com/watch?v=ELeZAKCN4tY


There is a good reason I'm not migrating to rust: I have 15million lines of C++ that we have written over the years, for a cost of hundreds of millions of dollars (probably over a billion by now). There is no way we can migrate to rust for less than more hundreds of millions, there is also the loss of new features that our competition can add while we are doing the migration effort.

I'm looking at how to fit rust into our project, but it isn't easy. I can report already that bad programmers in rust write worse code than great programmers in C++...


Often not possible when working on existing C++ codebase. C++ is here to stay...


Why would you migrate from a language full of :: and <> and {} which forces you to think about weird concepts about memory, ownership, sharing and pointers, to migrate to a very similar language?

It's like stopping huffing paint to start huffing petrol.


While I don't agree to migrate, I do agree that new projects need to find a safer alternative to C++, do we have a better mature alternative at this point in time other than Rust? I'm not aware of any other that is production ready.

Also if your only complain in syntax then is just your taste, I would have considered if you have complains about issues with the language, one that I can think of is async/await that is a WIP.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: