6 ms·
std::launder: the most obscure new feature of C++17 (2016)
- CraigRo 3y agoThis is an April folks joke
- hifromwork 3y agoI don't think this is true
- dgfitz 3y agoIs it? https://news.ycombinator.com/item?id=30017204 https://news.ycombinator.com/item?id=30017204
- perihelions 3y agoThe C++ language standard is not a funny joke.
- MaxBarraclough 3y agoAgreed. Brevity is the soul of wit, and all that.
- 1letterunixname 3y agoIt's the art of making the juggling with swords seem safe and easy while making a daily commute through a minefield of UB seem routine.
- MaxBarraclough 3y agoAnd there's a second minefield called the portable build solution, but we don't talk about it much.
- avidphantasm 3y ago> Don’t ask. If you’re not one of the 5 or so people in the world who already know what this is, you don’t want or need to know. The attitude rings true though. I am convinced that C++ is proof that we have discovered alien technology, and it is awful.
- ericdfoley 3y agoThe thing is that there is probably a lot of existing C++ code that is UB without std::launder (similarly to aliasing rules.) The main problem is that the C++ object lifetime rules are not well understood by most people writing C++ code.
- sqeaky 3y agoI hadn't even considered the task of going through old code and using this to make it more compliant, this is a great use case for this feature.
- MaxBarraclough 3y agoIt is not. It links to a lengthy StackOverflow thread about std::launder. https://stackoverflow.com/questions/39382501/ https://stackoverflow.com/questions/39382501/
- avrionov 3y agoIt is a feature: https://en.cppreference.com/w/cpp/utility/launder https://en.cppreference.com/w/cpp/utility/launder
- tux3 3y agoAs far as complicated features that very few people understand or use and that are hard to implement correctly in compilers, std::launder ranks pretty high. Topping the list, for me, would be memory_order_consume. It's so complicated and for such a slight extremely technical memory ordering optimization, compilers have mostly given up hope of ever implementing it. There was even talk of outright removing it from C++, but looks like it still stands today. I've never seen it used correctly (and even if it were, compilers just throw up their hands at it)
- ric129 3y agoI recall plenty of implementations turning into the same as a memory_order_acquire, which seems fine these days
- loeg 3y ago> On all mainstream CPUs other than DEC Alpha, dependency ordering is automatic, no additional CPU instructions are issued for this synchronization mode, only certain compiler optimizations are affected (e.g. the compiler is prohibited from performing speculative loads on the objects that are involved in the dependency chain). > Note that currently (2/2015) no known production compilers track dependency chains: consume operations are lifted to acquire operations. https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Consume_ordering https://en.cppreference.com/w/cpp/atomic/memory_order#Releas...
- dvt 3y ago> that prevents the optimizer from performing constant propagation I understand how it works, and why you would even maybe want this, but this just straight-up seems like a mistake. It breaks const-invariance, which I guess is no longer invariant. Is just any proposal making into C++ these days? > He tells us that this function might be handy when dealing with containers of const-qualified elements. Then just.. don't.. const-qualify your elements? What a neat footgun, not even consts are safe in C++ now.
- amluto 3y agoC++’s const was never especially safe — contemplate what mutable does. And that one can cast pointers-to-nonconst to pointer-to-const.
- kimixa 3y agoIt's always been a "programmer aid annotation" rather than anything that really affects code generation. The only possible difference (from the resulting binary POV) I can think of is "static const" variables might be allocated in a read-only executable section?
- throwway120385 3y agoProbably not, given the possibility that they can be const_casted back into mutable values. Locating static const values in read-only pages would result in crashes from valid statements in the language. In other words if you put a static const in a read only page, it would probably be considered a bug in your linker.
- actionfromafar 3y agoThat doesn't rhyme with my understanding of C++ (which is limited, of course). This sounds like undefined.
- secondcoming 3y agoAren't they put into the .rodata section of the binary? Crashing is exactly what happens, thankfully https://godbolt.org/z/vKj9dcPMc https://godbolt.org/z/vKj9dcPMc
- hardlianotion 3y agoThere are so many things that engineers want to simplify their lives that don’t appear to be prioritised for the standard library, so it is rather surprising to see something like this, which can only complexify.
- sqeaky 3y agoThis isn't my example, but consider this situation: you are maintaining an old code base that has stuff from 30 to 40 years ago in it because it's still working and still making the company money. But it is old, came from before we understood dependency management, and came from before we had tests as a standard practice. Parts of it have to be built on some old compiler because no one has taken the effort to rewrite it and get it to work on the new compiler. This hasn't been done because millions of developer hours have been put into it and it could take hundreds of thousands of developer hours to redo it. An obvious first step is to start by writing tests, and when you do so you can build little pieces of the old code on the new compiler but sometimes it produces wrong answers. If the old compiler worked a certain way and the new compiler works a different way it is often because the new compiler has a better optimizer and leverages better understandings of the assumption that most developers make. But some "clever" developer from back in the day did some shenanigans and leveraged undefined behavior that happened to do what they wanted. The maintenance options are either to leave it on the old compiler, rewrite the whole thing and hope you make it work right, or use std::launder to make the undefined behavior go away and hopefully make a minimal changes to retain the old behavior. In this case launder is a middle path that hopefully lets maintainers keep most of the old code with the new platform, but hopefully without having to rewrite a huge amount of it.
- renewiltord 3y agoWait this is crazy. What's the legitimate use-case? Man I would hate to work on codebases that have these invariants violated.
- plorkyeran 3y agoThe original use case was that std::vector's API was specifically designed to make it possible to have a vector of a type with const members, but it turned out to be impossible to implement without hitting UB. std::launder was introduced as a way to make the obvious implementation correct. Since then the object lifetime rules were adjusted to make it unnecessary for that.
- renewiltord 3y agoOh interesting. Thank you.
- jandrewrogers 3y agoOne of the main legitimate use cases for this feature is managing how the compiler interprets the lifetimes of runtime objects that are explicitly paged to disk. Many code bases rely on undefined behavior where the compiler coincidentally produces the expected behavior, which usually works, but I have seen occasional bugs in the wild from when it doesn't. You can use std::launder to guarantee that the compiler correctly interprets the lifetime of objects with these properties.
- kazinator 3y ago> explicitly paged to disk Example would help. Most paging nowadays is implicit, transparent to the program. Are you talking about some old-school overlays or something? Multiple objects in mass storage are mapped to the same address in memory, multiplexed in the time domain?
- zamalek 3y ago> Example would help. Almost any database.
- jandrewrogers 3y agoPaging is not transparent in high-scale and high-performance databases when using direct I/O to disk. It is not possible to make it transparent on many larger servers even if you wanted to because the silicon does not support a large enough virtual address space. This is a pretty common design problem in databases, or anything with huge amounts of data and storage really. There were magic incantations that compilers informally respected to induce the correct behavior but it wasn’t always reliable and technically not a bug when it wasn’t. This provides an official and simple way to achieve the same effect without obscure magic.
- loeg 3y agoAre high performance databases embedding non-POD C++ objects in explicitly paged memory?
- pavlov 3y ago“Jim, management is complaining that we can’t hire anyone for the open C++ developer positions because the interviews are all about std::launder. What’s up?” “Don’t you want to hire a top expert? It says right here that only five people in the world understand this feature. It’s the perfect filter to ensure that we don’t get random nobodies working on our legacy Win32 MFC application that manages hotel breakfast reservations. Trust the signal.”
- bingo3131 3y agoA post about an obscure C++ feature on Hacker News? Comments are going to be a dumpster-fire as usual. https://en.cppreference.com/w/cpp/utility/launder https://en.cppreference.com/w/cpp/utility/launder "template <class T> [[nodiscard]] constexpr T* launder (T* p) noexcept; Provenance fence with respect to p. Returns a pointer to the same memory that p points to, but where the referent object is assumed to have a distinct lifetime and dynamic type." It's a function for the compiler for low-level memory management and lifetime management code (i.e. code almost no C++ "end-user" writes) to turn off compile-time tracking and optimisations that might not be correct. Typically only used if you're starting the lifetime of one object over or inside another. Essentially, when you want the compiler to be dumb you launder the pointer to make the compiler intentionally forget the complex compile-time state tracking that compilers do and make the compiler pretend that pointer is actually a brand new object it knew nothing about. Someone brought up the volatile keyword: volatile is for turning off compiler assumptions about what a value might be at run-time. For example, if you read from a regular int twice in a row with no write in between, then the compiler would likely remove the second read and reuse the first value (better code-gen) as it knows the value could not have changed. The volatile keyword is how you tell the compiler that it cannot reliably observe all changes to the variable so every read must be performed (same for writes). launder and volatile are similar in so much that they exist to tell the compiler not to make assumptions about the values/objects, but that's about it. They are not interchangeable. But let's all pretend this function is something everyone using C++ needs to use to farm some internet points.
- fancyfredbot 3y agostd::launder has now become 'famously obscure'. I liked it before it was cool but nowadays indie kids like me prefer std::hardware_destructive_interference_size (https://en.cppreference.com/w/cpp/thread/hardware_destructive_interference_size https://en.cppreference.com/w/cpp/thread/hardware_destructiv...)