11 ms·
Why introduce `std::launder` rather than have the compiler take care of it?
- aaaaaaaaaaab 5y agoSo many people are weirded out in this thread, but unless you use placement-new there’s no need to know about this at all… This is just an escape hatch to solve a weird interaction between const members and placement-new.
- codeflo 5y agoEverything in C++ is just there to solve a weird interaction between <feature that’s in your codebase> and <feature that’s also in your codebase>. The “just learn a subset” crowd is wrong, you really do need to know everything.
- ATsch 5y agoYou also need to learn what placement new is and how it is used to know if you or any of your libraries are using it in the first place.
- Rexxar 5y agostd::vector use placement new and you don't need to know it to use std::vector correctly.
- ATsch 5y agoIf you don't understand what placement new is, you don't know whether libraries using placement new affects you. I did not write this comment about placement new specifically. It's just a thing that annoys me about the "learn a subset" idea. You still need to know at least enough about every feature to know whether it affects you. Placement new is perhaps not the best example there because it is relatively niche and self contained, true.
- google234123 5y agoIf you don't understand all the 10s of million of line of linux code, you don't know whether you are using linux correctly.
- spoiler 5y agoIf you're going to try to be clever/snide, at least come up with a better analogy... Using Linux effectively doesn't mean you need to learn its source code. You need to know about its features (and trade-off, etc). You don't need to know a language implementation's (e.g. gcc/clang for C++) source code to use a language well either, do you? Obviously you don't; it's a fools errand if all you ever want is to use it effectively. You need to know about features (and trade-off, etc), how they were designed in isolation, and more importantly how they were designed to fit/connect together.
- google234123 5y agoShow me some basic code using std vector that would change if the programmer knew more about placement new.
- google234123 5y agoNo you don’t.
- saagarjha 5y agoNot if they don’t expose it to you via their API. Very few libraries will do this.
- gpderetta 5y agoInterestingly one of the reasons launder exist is that without it std::vector is not implementable within the strict letter of the standard. IIRC the issue was that vector construct one object at a time but then access it as if it was part of an array which was never constructed
- aaaaaaaaaaab 5y agoGotta love these C++ FUD arguments! Can you tell us an example where a library’s internal usage of placement new results in bugs unless the consumers use std::launder?
- tsimionescu 5y agoIsn't this exactly what this argument shows? In older versions of C++, if you have an object with a non-const sub-object with a const member, and you give this object to a library, and then that library uses placement new to replace the sub-object within your object, you had to use std::launder to keep referring to the fields of your object, or you'd invoke UB. In newer C++, thankfully, this is no longer required. Edit: found a committee paper discussing exactly such cases: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0532r0.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p053... Obj x; x.use(); // ok mutate(x); // does this call placement new? x.use(); // may have undefined behavior std::launder(&x)->use(); // may be necessary x.use(); // may still have undefined behavior
- Animats 5y agoI tended, in my C++ days, to think that if you need "reinterpret_cast", you're doing it wrong. Now that I code in safe Rust, I still think that. If you really want to abstract this sort of thing, a good abstraction would be a write-only type, "space", representing memory with no content. Then make it possible to destroy an object and convert it to empty "space", or construct an object on empty "space". This creates a clear distinction between reusing memory and abusing the type system.
- erwincoumans 5y agoDo you find any issues with Rust that bothers you, as a former C++ developer? I'm still in my C++ days, but I avoid reinterpret_cast, as well as RTTI and C++ exceptions. Looking forward trying out Rust.
- Animats 5y agoThe biggest headache I've hit is that you can't have back references. When A owns B, it's really hard to get from B to A. You have to reference count everything, even if B is a field of A. A key concept in Rust is that no code can have access to two mutable references to the same object at the same time. That's the issue with std::launder, of course. The Rust mechanism for doing it enforces stronger restrictions than absolutely necessary. Not that enforcing the minimal set of restrictions is easy. The general argument of Rust enthusiasts is that you don't need that. But many of them are writing web back-end stuff, which does not have much state. I'm writing a client for a virtual world, which has an entire visible scene of constantly changing state. Representations for that sort of thing have extensive cross-links. Hammering that into the Rust model tends to result in things such as having to look up things in hashes where you'd use a direct link in C++. What's desirable is safe single ownership with backlinks. That's hard. You need something like a weak reference to a singly owned object, along with the compile time checking needed to prevent its misuse. Right now, you can do that with reference counted weak links, which are checked at run time. But you're often calling ".borrow()" to follow a link, and that will fail if the mutable borrow count becomes > 1. If that check could be replaced with static analysis by the borrow checker, more safe data structures would be possible. Trees with backlinks, doubly linked lists, etc. Not having this means you can reach the point where your program is one error away from compiling, and days of rewrite are needed to fix the problem. This is where unsafe code tends to sneak in, as an escape hatch.
- jokoon 5y agoI think someone should fork a new language from C++ and remove all the stuff that could be deprecated. I don't mean to make a new language like Zig or rust or nim. I mean just a "saner" C++ without all the backward compatibility that is holding back the language.
- skocznymroczny 5y agoJust use D. D is a saner C++.
- grumpyprole 5y agoIsn't part of the problem that no one can agree on the best subset? Compilers could provide pragmas and switches to enable projects to define their own language subset.
- MaxBarraclough 5y agoA fair point, but the major C++ compilers don't make much effort in letting you define a subset to permit. For contrast, the Ada language (which is larger than C but smaller than C++) takes this idea quite seriously. There are various 'well known' subsets of Ada with interesting properties and tooling. These subsets are called profiles. There's SPARK, a very minimalist subset tailored for formal verification, and Ravenscar, for concurrent hard real-time systems. Profile compliance is checked by the compiler itself. (If I understand correctly, the profiles are defined using Ada's rough equivalent of #pragma in C and C++.) In the C and C++ worlds there are subsets like Google's C++ style guide, LLVM's C++ style guide, MISRA C, and MISRA C++, but their tools (i.e. static analysis tools to check for compliance) are generally separate from the compiler, for what that's worth.
- XorNot 5y agoThis would argue in favor of several languages. Which would be fine - maybe we need several, maybe one would clearly win out.
- shakna 5y agoBetterC [0] is that, for me. It's a subset of D, that only relies on the C Standard Library. So all the features and syntax of D that is sane, without any of the extras that people find go too far beyond a system's language. You still get all the compile-time constructions, RAII, memory protection, lambdas, modules and so on. [0] https://dlang.org/spec/betterc.html https://dlang.org/spec/betterc.html
- eps 5y agoOi vey. This sort of QA is exactly what's wrong with the "modern" C++. It's just ugly. I've been using C++ as my main language since it was barely out of C with Classes stage and it pains me to see how it evolved from a language that extended C in clever and welcomed ways into this piece of committee-designed monstrosity with not a trace of its former elegance left in it.
- snickerbockers 5y agoIt's absolutely disgusting how many of C++'s recent additions exist to work around problems introduced by C++'s other recent additions.
- bigcheesegs 5y agoDo you have any examples? std::launder fixes an issue that has existed since C++98.
- tialaramex 5y agoIn C++ 03 they realise their pointer (inherited from C) is awful. Do they fix it? No, they add a new type named std::auto_ptr which is "smart". Thanks to operator overloading it can behave like the existing pointer. Kind of. std::auto_ptr is pretty bad, and so in C++ 11 they deprecate auto_ptr and introduced std::shared_ptr and std::unique_ptr so now finally their language has halfway usable pointers, with these unwieldy names and some odd semantics you just have to get used to. C-style pointers remain all of: Simpler to use by virtue of their terse syntax, still necessary, and unsafe. std::auto_ptr still exists forever, but is officially deprecated. At first C lacks strings, promoting string literals to a strange array with an extra zero value in it. Eventually C++ gets std::string and std::wstring but, nothing of value about these strings is defined, so they're both pretty useless and of course dangerous. In C++ 17 it gets std::string_view which finally expresses one of the things you probably first wanted, but it provides no enforcement of the most obvious expectation you have - C++ allows a string_view to outlive the underlying string, causing Undefined Behaviour. In C++ 20 you get to use ranged behaviour, and, that extra zero value bites you hard because of course you didn't mean the zero value but in C++ that's "part" of your string. They also, finally, decide that UTF-8 might be a good idea and define yet another type of string to mean UTF-8 encoded, about five years after everybody who matters was of course encoding strings as UTF-8.
- MaxBarraclough 5y agoThere's an error in the title, it should be std::launder rather than std:launder.
- dang 5y agoFixed. Thanks!
- codeflo 5y agoThis confuses me even more than C++ usually does. From the first answer: > struct foo{ int const x; }; > void some_func(foo*); > int bar() { > foo f { 123 }; > some_func(&f); > return f.x; > } > bar will always return 123. The compiler may generate code that actually accesses the object. But the object model does not require this. f.x is a const object (not a reference/pointer to const), and therefore it cannot be changed. I like to think I know quite a bit about C++, but I don’t get this at all. Why is f.x a const object even when accessed through a non-const variable? f isn’t const; there’s no const_cast here. At first glance, this looks like a bug in the spec, roughly like confusing int const *p (pointer to const) with int const *const p (const pointer to const). Only the latter will always point to the same thing. What am I missing? (Edit: Since it’s a bit hidden in the SO question, the idea is that some_func does something like this: void some_func(foo *f) { new(f) foo { 42 }; } Note that there’s no const_cast here, and f’s storage isn’t const, so this isn’t UB to the best of my knowledge. BTW, in case it’s not obvious, it’s not all that helpful to reply to the question why the spec is a certain way by tautologically repeating the spec.) (Edit 2: Unfortunately also very typical for C++ discussions, I just love how people think that C++ confusing me must mean that I’m dumb, and then condescendingly post a wrong answer. Rule of thumb: If you’re confident in your ability to understand C++, you don’t understand it very well.)
- ptr 5y agoThe constiness of a pointer can be casted away while the constiness of a value variable cannot — it’s UB. foo::x is declared const, so it’s always const.
- dkackman11 5y agofurther evidence that modern C++ is an esoteric language
- Shadonototra 5y agoactually it is easier to understand than borrow checker from rust a function is much better, it's explicit