Are you over 18 and want to see adult content?
More Annotations
Que comen, Donde viven | Tipos y características de los animales.
Are you over 18 and want to see adult content?
Welcome! - RPG Market Generator
Are you over 18 and want to see adult content?
Shari Schreiber - Emotional Healing - Do it yourself
Are you over 18 and want to see adult content?
Home | Lucas Oil Off Road Racing Series
Are you over 18 and want to see adult content?
A complete backup of tlcbythelake.com
Are you over 18 and want to see adult content?
GuruDroid.net - правильная настройка Андроид телефона и планшета
Are you over 18 and want to see adult content?
หางานทำ หารายได้เสริม รายได้พิเศษ งานเสริมรายได้ หางานพิเศษ งานทำที่บ้าน
Are you over 18 and want to see adult content?
WordSense Dictionary: word origin & history, definitions, synonyms & translations
Are you over 18 and want to see adult content?
Favourite Annotations
A complete backup of universalhunt.com
Are you over 18 and want to see adult content?
A complete backup of sarcasticcooking.com
Are you over 18 and want to see adult content?
A complete backup of fresh2refresh.com
Are you over 18 and want to see adult content?
Text
SUTTER’S MILL
The function asserts that p is not null, and then on the next line unconditionally dereferences p and scribbles over the location it points to. If p is null and the assertion checking is off so that we can get to the next line, the compiler is allowed to make running the whole program format our hard drive. (b) possibly results in undefined behavior. A general way to describe this class of TRIP REPORT: SUMMER 2021 ISO C++ STANDARDS MEETING On Monday, the ISO C++ committee held its third full-committee (plenary) meeting of the pandemic and adopted a few more features and improvements for draft C++23. We had representatives from 17 voting nations at this meeting: Austria, Bulgaria, Canada, Czech Republic, Finland, France, Germany, Israel, Italy, Netherlands, Poland, Russia, Slovakia, Spain, Switzerland, United Kingdom, and C++20 APPROVED, C++23 MEETINGS AND SCHEDULE UPDATE C++23 schedule and priorities. The C++23 schedule (P1000R4) and C++23 priorities (P0592R4) are unaffected by the pandemic. You may find this surprising, but that’s because the committee is on a “train model” that focuses on schedule and priorities for each release, instead of a specific feature set. One of the benefits of the trainmodel
GOTW #102: ASSERTIONS AND “UB” (DIFFICULTY: 7/10) This special Guru of the Week series focuses on contracts. Now that we have considered assertions, postconditions, and preconditions in GotWs #97-101, let’s pause and reflect: To what extent does a failed contract imply “UB” either the Hidden Dragon of Undefined Behavior, or the Crouching Tiger of Unspecified Behavior? JG Question1.
MOVE, SIMPLY
C++ "move" semantics are simple, and unchanged since C++11. But they are still widely misunderstood, sometimes because of unclear teaching and sometimes because of a desire to view move as something else instead of what it is. This post is an attempt to shed light on that situation. Thank you to the following for their EFFECTIVE CONCURRENCY: CHOOSE CONCURRENCY-FRIENDLY DATA The latest Effective Concurrency column, "Choose Concurrency-Friendly Data Structures", just went live on DDJ's site, and also appears in the print magazine. From the article: What is a high-performance data structure? To answer that question, we're used to applying normal considerations like Big-Oh complexity, and memory overhead, locality, and traversal order. EFFECTIVE CONCURRENCY: USE THREADS CORRECTLY = ISOLATION This month’s Effective Concurrency column, “Use Threads Correctly = Isolation + Asynchronous Messages”, is now live on DDJ’s website. From the article: Explicit threads are undisciplined. They need some structure to keep them in line. In this column, we're going to see what that structure is, as we motivate and illustrate bestpractices for using
TO STORE A DESTRUCTOR The short answer is to store two raw pointers: one to the object, and one to a type-erased destructor function that’s handy to write using a lambda. In deferred_heap.h, you’ll see that the library stores a deferred destructor as: So we store two raw pointers, a raw pointer to the object to be destroyed and a raw function pointer to the ATOMIC WEAPONS: THE C++ MEMORY MODEL AND MODERN HARDWARE atomic Weapons: The C++ Memory Model and Modern Hardware. Most of the talks I gave at C++ and Beyond 2012 last summer are already online at Channel 9. Here are two more. This is a two-part talk that covers the C++ memory model, how locks and atomics and fences interact and map to hardware, and more. Even though we’re talking about C++, much EFFECTIVE CONCURRENCY: ELIMINATE FALSE SHARING The final example in “Eliminate False Sharing” is a little unclear on the intent. The text says “we arbitrarily force half the workers to only perform reads from their result” but it appears the code does a read on about half the threads when an element in the matrix is odd (good) and a read and write, “++result”, for every thread when an element in the matrix is even (doh).SUTTER’S MILL
The function asserts that p is not null, and then on the next line unconditionally dereferences p and scribbles over the location it points to. If p is null and the assertion checking is off so that we can get to the next line, the compiler is allowed to make running the whole program format our hard drive. (b) possibly results in undefined behavior. A general way to describe this class of TRIP REPORT: SUMMER 2021 ISO C++ STANDARDS MEETING On Monday, the ISO C++ committee held its third full-committee (plenary) meeting of the pandemic and adopted a few more features and improvements for draft C++23. We had representatives from 17 voting nations at this meeting: Austria, Bulgaria, Canada, Czech Republic, Finland, France, Germany, Israel, Italy, Netherlands, Poland, Russia, Slovakia, Spain, Switzerland, United Kingdom, and C++20 APPROVED, C++23 MEETINGS AND SCHEDULE UPDATE C++23 schedule and priorities. The C++23 schedule (P1000R4) and C++23 priorities (P0592R4) are unaffected by the pandemic. You may find this surprising, but that’s because the committee is on a “train model” that focuses on schedule and priorities for each release, instead of a specific feature set. One of the benefits of the trainmodel
GOTW #102: ASSERTIONS AND “UB” (DIFFICULTY: 7/10) This special Guru of the Week series focuses on contracts. Now that we have considered assertions, postconditions, and preconditions in GotWs #97-101, let’s pause and reflect: To what extent does a failed contract imply “UB” either the Hidden Dragon of Undefined Behavior, or the Crouching Tiger of Unspecified Behavior? JG Question1.
MOVE, SIMPLY
C++ "move" semantics are simple, and unchanged since C++11. But they are still widely misunderstood, sometimes because of unclear teaching and sometimes because of a desire to view move as something else instead of what it is. This post is an attempt to shed light on that situation. Thank you to the following for their EFFECTIVE CONCURRENCY: CHOOSE CONCURRENCY-FRIENDLY DATA The latest Effective Concurrency column, "Choose Concurrency-Friendly Data Structures", just went live on DDJ's site, and also appears in the print magazine. From the article: What is a high-performance data structure? To answer that question, we're used to applying normal considerations like Big-Oh complexity, and memory overhead, locality, and traversal order. EFFECTIVE CONCURRENCY: USE THREADS CORRECTLY = ISOLATION This month’s Effective Concurrency column, “Use Threads Correctly = Isolation + Asynchronous Messages”, is now live on DDJ’s website. From the article: Explicit threads are undisciplined. They need some structure to keep them in line. In this column, we're going to see what that structure is, as we motivate and illustrate bestpractices for using
TO STORE A DESTRUCTOR The short answer is to store two raw pointers: one to the object, and one to a type-erased destructor function that’s handy to write using a lambda. In deferred_heap.h, you’ll see that the library stores a deferred destructor as: So we store two raw pointers, a raw pointer to the object to be destroyed and a raw function pointer to the ATOMIC WEAPONS: THE C++ MEMORY MODEL AND MODERN HARDWARE atomic Weapons: The C++ Memory Model and Modern Hardware. Most of the talks I gave at C++ and Beyond 2012 last summer are already online at Channel 9. Here are two more. This is a two-part talk that covers the C++ memory model, how locks and atomics and fences interact and map to hardware, and more. Even though we’re talking about C++, much EFFECTIVE CONCURRENCY: ELIMINATE FALSE SHARING The final example in “Eliminate False Sharing” is a little unclear on the intent. The text says “we arbitrarily force half the workers to only perform reads from their result” but it appears the code does a read on about half the threads when an element in the matrix is odd (good) and a read and write, “++result”, for every thread when an element in the matrix is even (doh). TRIP REPORT: SUMMER 2021 ISO C++ STANDARDS MEETING On Monday, the ISO C++ committee held its third full-committee (plenary) meeting of the pandemic and adopted a few more features and improvements for draft C++23. We had representatives from 17 voting nations at this meeting: Austria, Bulgaria, Canada, Czech Republic, Finland, France, Germany, Israel, Italy, Netherlands, Poland, Russia, Slovakia, Spain, Switzerland, United Kingdom, andNOVEMBER 2020
On Monday, the ISO C++ committee completed its final full-committee (plenary) meeting of 2020 and adopted the first changes to the C++23 working draft, including a few new features. This was a first in several ways: It was our first-ever virtual plenary, held online via Zoom. It was also our first-ever plenary meeting that wasn’t held atthe
ELEMENTS OF MODERN C++ STYLE Elements of Modern C++ Style. “C++11 feels like a new language.”. – Bjarne Stroustrup. The C++11 standard offers many useful new features. This page focuses specifically and only on those features that make C++11 really feel like a new language compared to C++98, because: They change the styles and idioms you’ll use when writingC++
C++ LIBRARIES: CASABLANCA At GoingNative in February, I emphasized the need for more modern and portable C++ libraries, including for things like RESTful web/cloud services, HTTP, JSON, and more. The goal is to find or develop modern C++ libraries that leverage C++11 features, and then submit the best for standardization. Microsoft wants to do its part, and here’s COMPLEX INITIALIZATION FOR A CONST VARIABLE I get the point but I seriously doubt if it is an advantage. It is not much different from calling a named function. If the complex calculation has a name I would a create a function with that name and call it with the necessary parameters. TO STORE A DESTRUCTOR The short answer is to store two raw pointers: one to the object, and one to a type-erased destructor function that’s handy to write using a lambda. In deferred_heap.h, you’ll see that the library stores a deferred destructor as: So we store two raw pointers, a raw pointer to the object to be destroyed and a raw function pointer to the EFFECTIVE CONCURRENCY: VOLATILE VS. VOLATILE This month's Effective Concurrency column, "volatile vs. volatile", is now live on DDJ's website and also appears in the print magazine. (As a historical note, it's DDJ's final print issue, as I mentioned previously.) This article aims to answer the frequently asked question: "What does volatile mean?" The short answer: "It depends, doyou mean
EFFECTIVE CONCURRENCY: PREFER USING ACTIVE OBJECTS INSTEAD This month’s Effective Concurrency column, “Prefer Using Active Objects Instead of Naked Threads,” is now live on DDJ’s website. From the article: Active objects dramatically improve our ability to reason about our thread's code and operation by giving us higher-level abstractions and idioms that raise the semantic level of our programand let us
JANUARY 2007
Essentially, exception specifications are a wonderful idea in basic principle, but no one really knows how to design them. There are two major approaches, and both have serious problems. Java chose static enforcement (at compile time, as suggested above), and C++ chose dynamic enforcement. READER Q&A: IS STD::ATOMIC_COMPARE_EXCHANGE Updated 8/26: Duncan's question is actually correct and compare_exchange should have the semantics he asks for. However, the answer to 'is it implementable' is I think still Yes. Quick answer: Yes. I see there was also a thread about this on StackOverflow, so I'll echo this Q&A publicly for others' benefit and hopefully todispel
SUTTER’S MILL
The function asserts that p is not null, and then on the next line unconditionally dereferences p and scribbles over the location it points to. If p is null and the assertion checking is off so that we can get to the next line, the compiler is allowed to make running the whole program format our hard drive. (b) possibly results in undefined behavior. A general way to describe this class of MARCH 2021 – SUTTER’S MILL Wrong value (3 ways): Again as in (a), we have the implicit precondition that idx_min idx_max would be wrong, but would silently compile. But this time there are two additional ways to go wrong, because idx_min and idx_max must both be valid subscripts into container, so if either is outside the range [0, container.size()) it is a valid integer but an out of C++20 APPROVED, C++23 MEETINGS AND SCHEDULE UPDATE C++23 schedule and priorities. The C++23 schedule (P1000R4) and C++23 priorities (P0592R4) are unaffected by the pandemic. You may find this surprising, but that’s because the committee is on a “train model” that focuses on schedule and priorities for each release, instead of a specific feature set. One of the benefits of the trainmodel
ELEMENTS OF MODERN C++ STYLE Elements of Modern C++ Style. “C++11 feels like a new language.”. – Bjarne Stroustrup. The C++11 standard offers many useful new features. This page focuses specifically and only on those features that make C++11 really feel like a new language compared to C++98, because: They change the styles and idioms you’ll use when writingC++
MOVE, SIMPLY
C++ "move" semantics are simple, and unchanged since C++11. But they are still widely misunderstood, sometimes because of unclear teaching and sometimes because of a desire to view move as something else instead of what it is. This post is an attempt to shed light on that situation. Thank you to the following for their GOTW #91 SOLUTION: SMART POINTER PARAMETERS GotW #91 Solution: Smart Pointer Parameters. Herb Sutter GotW 2013-06-05. 2013-12-03. 9 Minutes. NOTE: Last year, I posted three new GotWs numbered #103-105. I decided leaving a gap in the numbers wasn’t best after all, so I am renumbering them to #89-91 to continue the sequence. Here is the updated version of what was GotW#105.
ATOMIC WEAPONS: THE C++ MEMORY MODEL AND MODERN HARDWARE atomic Weapons: The C++ Memory Model and Modern Hardware. Most of the talks I gave at C++ and Beyond 2012 last summer are already online at Channel 9. Here are two more. This is a two-part talk that covers the C++ memory model, how locks and atomics and fences interact and map to hardware, and more. Even though we’re talking about C++, much EFFECTIVE CONCURRENCY: CHOOSE CONCURRENCY-FRIENDLY DATA The latest Effective Concurrency column, "Choose Concurrency-Friendly Data Structures", just went live on DDJ's site, and also appears in the print magazine. From the article: What is a high-performance data structure? To answer that question, we're used to applying normal considerations like Big-Oh complexity, and memory overhead, locality, and traversal order. READER Q&A: KEYWORDS AND ATTRIBUTES Referring to C++ AMP, a reader emailed me to ask:. Are you going to replace restrict keyword with new C++11 attribute feature ?. No, because restrict is a language feature and are specifically designed to be ignorable and shouldn’t be used for things having language semantic meaning.During the ISO C++11 process, I was heavily involved in a long battle to try to GOTW #88: A CANDIDATE FOR THE “MOST IMPORTANT CONST GotW #88: A Candidate For the “Most Important const”. Herb Sutter C++ 2008-01-01 3 Minutes. A friend recently asked me whether Example 1 below is legal, and if so what it means. It led to a nice discussion I thought I’d post here. Since it was in close to GotW style already, I thought I’d do another honorary one after all these yearsSUTTER’S MILL
The function asserts that p is not null, and then on the next line unconditionally dereferences p and scribbles over the location it points to. If p is null and the assertion checking is off so that we can get to the next line, the compiler is allowed to make running the whole program format our hard drive. (b) possibly results in undefined behavior. A general way to describe this class of MARCH 2021 – SUTTER’S MILL Wrong value (3 ways): Again as in (a), we have the implicit precondition that idx_min idx_max would be wrong, but would silently compile. But this time there are two additional ways to go wrong, because idx_min and idx_max must both be valid subscripts into container, so if either is outside the range [0, container.size()) it is a valid integer but an out of C++20 APPROVED, C++23 MEETINGS AND SCHEDULE UPDATE C++23 schedule and priorities. The C++23 schedule (P1000R4) and C++23 priorities (P0592R4) are unaffected by the pandemic. You may find this surprising, but that’s because the committee is on a “train model” that focuses on schedule and priorities for each release, instead of a specific feature set. One of the benefits of the trainmodel
ELEMENTS OF MODERN C++ STYLE Elements of Modern C++ Style. “C++11 feels like a new language.”. – Bjarne Stroustrup. The C++11 standard offers many useful new features. This page focuses specifically and only on those features that make C++11 really feel like a new language compared to C++98, because: They change the styles and idioms you’ll use when writingC++
MOVE, SIMPLY
C++ "move" semantics are simple, and unchanged since C++11. But they are still widely misunderstood, sometimes because of unclear teaching and sometimes because of a desire to view move as something else instead of what it is. This post is an attempt to shed light on that situation. Thank you to the following for their GOTW #91 SOLUTION: SMART POINTER PARAMETERS GotW #91 Solution: Smart Pointer Parameters. Herb Sutter GotW 2013-06-05. 2013-12-03. 9 Minutes. NOTE: Last year, I posted three new GotWs numbered #103-105. I decided leaving a gap in the numbers wasn’t best after all, so I am renumbering them to #89-91 to continue the sequence. Here is the updated version of what was GotW#105.
ATOMIC WEAPONS: THE C++ MEMORY MODEL AND MODERN HARDWARE atomic Weapons: The C++ Memory Model and Modern Hardware. Most of the talks I gave at C++ and Beyond 2012 last summer are already online at Channel 9. Here are two more. This is a two-part talk that covers the C++ memory model, how locks and atomics and fences interact and map to hardware, and more. Even though we’re talking about C++, much EFFECTIVE CONCURRENCY: CHOOSE CONCURRENCY-FRIENDLY DATA The latest Effective Concurrency column, "Choose Concurrency-Friendly Data Structures", just went live on DDJ's site, and also appears in the print magazine. From the article: What is a high-performance data structure? To answer that question, we're used to applying normal considerations like Big-Oh complexity, and memory overhead, locality, and traversal order. READER Q&A: KEYWORDS AND ATTRIBUTES Referring to C++ AMP, a reader emailed me to ask:. Are you going to replace restrict keyword with new C++11 attribute feature ?. No, because restrict is a language feature and are specifically designed to be ignorable and shouldn’t be used for things having language semantic meaning.During the ISO C++11 process, I was heavily involved in a long battle to try to GOTW #88: A CANDIDATE FOR THE “MOST IMPORTANT CONST GotW #88: A Candidate For the “Most Important const”. Herb Sutter C++ 2008-01-01 3 Minutes. A friend recently asked me whether Example 1 below is legal, and if so what it means. It led to a nice discussion I thought I’d post here. Since it was in close to GotW style already, I thought I’d do another honorary one after all these years TRIP REPORT: SUMMER 2021 ISO C++ STANDARDS MEETING 1 day ago · On Monday, the ISO C++ committee held its third full-committee (plenary) meeting of the pandemic and adopted a few more features and improvements for draft C++23. We had representatives from 17 voting nations at this meeting: Austria, Bulgaria, Canada, Czech Republic, Finland, France, Germany, Israel, Italy, Netherlands, Poland, Russia, Slovakia, Spain, Switzerland, United Kingdom, and MARCH 2021 – SUTTER’S MILL Wrong value (3 ways): Again as in (a), we have the implicit precondition that idx_min idx_max would be wrong, but would silently compile. But this time there are two additional ways to go wrong, because idx_min and idx_max must both be valid subscripts into container, so if either is outside the range [0, container.size()) it is a valid integer but an out of C++ – SUTTER’S MILL Wrong value (3 ways): Again as in (a), we have the implicit precondition that idx_min idx_max would be wrong, but would silently compile. But this time there are two additional ways to go wrong, because idx_min and idx_max must both be valid subscripts into container, so if either is outside the range [0, container.size()) it is a valid integer but an out of GOTW #100: COMPILATION FIREWALLS (DIFFICULTY: 6/10JG
Questions 1. What is the Pimpl Idiom, and why is it useful? Guru Questions 2. What is the best way to express the basic Pimpl Idiom in C++11? 3. What parts of the class should go into the impl object? Some potential options include: GOTW-ISH SOLUTION: THE ‘CLONABLE’ PATTERN This is the solution to GotW-ish: The ‘clonable’ pattern.. In summary, a distinguished C++ ISO C++ committee expert emailed me toask: [To avoid
ATOMIC WEAPONS: THE C++ MEMORY MODEL AND MODERN HARDWARE atomic Weapons: The C++ Memory Model and Modern Hardware. Most of the talks I gave at C++ and Beyond 2012 last summer are already online at Channel 9. Here are two more. This is a two-part talk that covers the C++ memory model, how locks and atomics and fences interact and map to hardware, and more. Even though we’re talking about C++, much READER Q&A: KEYWORDS AND ATTRIBUTES Referring to C++ AMP, a reader emailed me to ask:. Are you going to replace restrict keyword with new C++11 attribute feature ?. No, because restrict is a language feature and are specifically designed to be ignorable and shouldn’t be used for things having language semantic meaning.During the ISO C++11 process, I was heavily involved in a long battle to try to COMPLEX INITIALIZATION FOR A CONST VARIABLE I get the point but I seriously doubt if it is an advantage. It is not much different from calling a named function. If the complex calculation has a name I would a create a function with that name and call it with the necessary parameters. EFFECTIVE CONCURRENCY: USE THREADS CORRECTLY = ISOLATION This month’s Effective Concurrency column, “Use Threads Correctly = Isolation + Asynchronous Messages”, is now live on DDJ’s website. From the article: Explicit threads are undisciplined. They need some structure to keep them in line. In this column, we're going to see what that structure is, as we motivate and illustrate bestpractices for using
EFFECTIVE CONCURRENCY: KNOW WHEN TO USE AN ACTIVE OBJECT This month’s Effective Concurrency column, “Know When to Use an Active Object Instead of a Mutex,” is now live on DDJ’s website.. From the article: Let’s say that your program has a shared log file object. The log file is likely to be a popular object; lots of different threads must be able to write to the file; and to avoid corruption, we need to ensure that only one thread may beSkip to content
SUTTER’S MILL
Herb Sutter on software development THE VARNA ISO C++ MEETING IS POSTPONED Yesterday morning, I announced to the committee that the next ISO WG21 (C++) meeting originally planned for June 1-6 in Varna, Bulgaria, has been postponed due to the current health situation. We appreciate very much all the hard work and expense that our hosts, VMware and Chaos Group, have invested in welcoming us to their beautiful country for our first Bulgarian meeting! And we haven’t given up: We still hope to meet in Varna as soon as possible, but it will be sometime after 2020. In the meantime, our current plan is to continue with our existing meeting schedule,
and hold our next face-to-face ISO C++ meeting in New York City this November, subject of course to global developments as all of us throughout the world deal with this emergency together. We all love C++, but our first priority is the health and safety of all of our experts and observers, all of our families, and of the global community. The ISO C++ committee leadership (about 60 current and former officers and chairs) had already been monitoring the situation closely and making fallback plans. Then the decision was made for us yesterday morning when, shortly after WHO declared a pandemic, ISO issued a global ban on all face-to-face standards meetings through at least June 30: https://platform.twitter.com/widgets.js Interestingly, the ISO Secretary-General’s announcement included the note that approximately 275 ISO meetings scheduled to happen between 1 Feb and 30 June had already been cancelled, which gives a glimpse into the scope and scale of ISO standards work. In the meantime, progress will continue. Many WG21 subgroups have already been having regular online meetings between our full face-to-face meetings, and we will expand that and have more subgroups making progress using ISO’s online meeting facilities throughout the spring and summer. But above all, please everyone be safe, take this crisis seriously, and follow the instructions on social distancing and isolation — by doing that we will all help ourselves and our communities. Of course this will still get worse before it gets better, but we are not helpless: The actions that we as individuals and communities are taking right now are going to make a major difference in reducing the damage done, because most of the potential damage is still ahead of us where we can influence it. It’s hard to know yet how soon it will be before our conferences and standards meetings will resume as usual, because the situation is still changing rapidly. But we’ll keep watching, we’ll keep staying safe not just for our own sake but also to minimize danger to others, and after it’s over I look forward to seeing many of you again, face to face, at our regular events in the hopefully-nearfuture.
Herb Sutter Uncategorized 2020-03-132020-03-142 Minutes
REFERENCES, SIMPLY
_References are for parameter passing, including range-for. Sometimes they’re useful as local variables, but pointers or structured bindings are usually better. Any other use of references typically leads to endless design debates. This post is an attempt to shed light on this situation, and perhaps reduce some of the time spent on unresolved ongoing design debates in the C++ community. Thank you to the following for their feedback on drafts of this material: Howard Hinnant, Arthur O’Dwyer, Richard Smith, Bjarne Stroustrup, VilleVoutilainen._
_Edited to add: mention the core language specification complexity, and that the list of examples is not exhaustive and other examples fall into the same categories as listed examples._REFERENCES
WHAT REFERENCES ARE AND HOW TO USE THEM IN C++, A C& OR C&& REFERENCE IS AN INDIRECT WAY TO REFER TO AN EXISTING OBJECT. EVERY REFERENCE HAS A DUAL NATURE: IT’S IMPLEMENTED UNDER THE COVERS AS A POINTER, BUT SEMANTICALLY IT USUALLY BEHAVES LIKE AN ALIAS BECAUSE MOST USES OF ITS NAME AUTOMATICALLY DEREFERENCE IT. (OTHER DETAILS ARE NOT COVERED HERE, INCLUDING THE USUAL PARAMETERPASSING RULES
AND THAT C&& HAS A DIFFERENT MEANING DEPENDING ON WHETHER C IS A CONCRETE TYPE OR A TEMPLATE PARAMETER TYPE.) C++ REFERENCES WERE INVENTED TO BE USED AS FUNCTION PARAMETER/RETURN TYPES, AND THAT’S WHAT THEY’RE STILL PRIMARILY USEFUL FOR. SINCE C++11, THAT INCLUDES THE RANGE-FOR LOOP WHICH CONCEPTUALLY WORKS LIKE A FUNCTION CALL (SEE Q&A). SOMETIMES, A REFERENCE CAN ALSO BE USEFUL AS A LOCAL VARIABLE, THOUGH IN MODERN C++ A POINTER OR STRUCTURED BINDING IS USUALLY BETTER (SEEQ&A).
THAT’S IT. ALL OTHER USES OF REFERENCES SHOULD BE AVOIDED. ADVANCED NOTE FOR EXPERTS Please see the Q&A for more, including const& lifetime extension, pairAPPENDIX: Q&A
HISTORICAL QUESTION: CAN YOU ELABORATE A LITTLE MORE ON WHY REFERENCES WERE INVENTED FOR FUNCTION PARAMETER/RETURN TYPES? Here is a summary, but for more detail please see _The Design and Evolution of C++_ (D&E) section 3.7, which begins: _“References were introduced primarily to support operator overloading…”_ In C, to pass/return objects to/from functions you have two choices: either pass/return a copy, or take their address and pass/return a pointer which lets you refer to an existing object. Neither is desirable for overloaded operators. There are two motivating use cases, both described in D&E: * The primary use case is that we want to pass an existing object to an operator without copying it. Passing by reference lets calling code write just a - b, which is natural and consistent with built-in types’ operators. If we had to write &a - &b to pass by pointer, that would be (very) inconvenient, inconsistent with how we use the built-in operators, and a conflict when that operator already has a different meaning for raw pointers as it does in this example. * Secondarily, we want to return an existing object without copying it, especially from operators like unary * and . Passing by reference lets calling code write str = 'a'; which is natural and consistent with built-in arrays and operators. If we had to write *str = 'a'; to return by pointer, that would be (slightly) inconvenient and also inconsistent with built-in operators, but not the end of the world and so this one is only a secondary motivatingcase.
Those are the only uses of references discussed in D&E, including in the section on smart references and operator., and the only places where references are really needed still today. WHAT WAS THAT ABOUT RANGE-FOR BEING LIKE A FUNCTION CALL? The C++11 range-for loop is semantically like function parameter passing: We pass a range to the loop which takes it as if by an auto&& parameter, and then the loop passes each element in turn to each loop iteration and the loop body takes the element in the way it declares the loop element variable. For example, this loop body takes its element parameter by const auto&:1
2
3
// Using range-for: The loop variable is a parameter to // the loop body, which is called once per loop iteration for (const auto& x : rng) { ... } If we were instead using the std::for_each algorithm with the loop body in a lambda, the parameter passing is more obvious: for_each takes the range via an iterator pair of parameters, and then calls the loop body lambda passing each element as an argument to the lambda’s parameter:1
2
// Using std::for_each: Basically equivalent for_each (begin(rng), end(rng), (const auto& x) { ... }); IS A REFERENCE A POINTER TO AN OBJECT, OR AN ALTERNATE NAME FOR THEOBJECT?
Yes — it is either or both, depending on what you’re doing at themoment.
This dual nature is the core problem of trying to use a reference as a general concept: Sometimes the language treats a reference as a pointer (one level of indirection), and sometimes it treats it as an alias for the referenced object (no level of indirection, as if it were an implicitly dereferenced pointer), but those are not the same thing and references make those things visually ambiguous. When passing/returning an object by reference, this isn’t a problem because we know we’re always passing by pointer under the covers and when we use the name we’re always referring to the existing object by alias. That’s clear, and references are well designed for use as function parameter/return types. But when trying to use references elsewhere in the language, we have to know which aspect (and level of indirection) we’re dealing with at any given time, which leads to confusion and woe. References have never been a good fit for non-parameter/return uses. And that is doubly sad, because supporting “reference types” throughout the language complicates the C++ core language specification, while simultaneously forcing us to keep teaching why to avoid using nearly all of that generalized language support. AREN’T LOCAL REFERENCES USEFUL BECAUSE OF LIFETIME EXTENSION? We “made it useful” as an irregular extension, but that’s brittle and now basically unnecessary as of C++17. A brief history of lifetime extension: After references were first added in the 1980s, C++ later added a special case where binding a temporary object to a local variable of type const& and still later auto&& (but not generally other kinds of local references) was “made useful” by imbuing only those references with the special power of extending the lifetime of a temporary object, just because we could (and because there were use cases where it was important for performance, before C++17 guaranteed copy elision). However, these cases have always been: * brittle and inconsistent (e.g., const T& t = f(); and const T& t = f().x; and struct X { const T& r; } x = { f() }; extend the lifetime of an object returned by value from f(), but const T& t = f().g(); does not); * irregular (e.g., T& t = f(); is ill-formed, whereas const T& t = f(); and T t = f(); still uniformly work); and * unnecessary now that C++17 has guaranteed copy elision (e.g., just write T t = f(); and the meaning is both obvious and correct, as well as way easier to teach and learn and use). AREN’T LOCAL REFERENCES USEFUL TO GET MEANINGFUL NAMES FOR PARTS OF AN OBJECT RETURNED FROM A FUNCTION? Yes, but since C++17 structured bindings are strictly better. For example, given a set1
2
3
4
5
// accessing the members of a pair directly (unmeaningful names) auto value = s.insert(4);if (value.second) {
do_something_with(value.first);}
Structured bindings lets us directly name the members — note that this just invents names for them, it does not create any actual pointer indirection:1
2
3
4
5
// using structured bindings (easy to use meaningful names) auto = s.insert(4);if (succeeded) {
do_something_with(position);}
In the olden days before structured bindings, some people like to use references to indirectly name the members — which like the above gives them readable names, but unlike the above does create new pointer-equivalent indirect variables and follows those pointers which can incur a little space and time overhead (and also isn’t asreadable)…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// using references (cumbersome, don't do this anymore) auto value = s.insert(4); auto& position = value.first; // equivalent topointers
auto& succeeded = value.second; if (succeeded) { // invisible dereference do_something_with(position); // invisibledereference
}
// or using pointers (ditto) auto value = s.insert(4); auto position = &value.first; // self-documentingpointers
auto succeeded = &value.second; if (*succeeded) { //visible dereference
do_something_with(*position); // visibledereference
}
… but even in the olden days, references were never significantly better than using pointers since the code is basically identical either way. Today, prefer structured bindings. AREN’T LOCAL REFERENCES USEFUL TO EXPRESS ALIASES, FOR EXAMPLE TO A MEMBER OF AN ARRAY OR CONTAINER? Yes, though pointers can do it equivalently, it’s a style choice. For example, this local reference is useful:1
2
auto& r = a;
// ... then use r repeatedly ... Or you can equivalently use a pointer:1
2
auto p = &a;
// ... then use *p repeatedly ... ISN’T T& CONVENIENT FOR EASILY EXPRESSING A POINTER THAN CAN’T BE REBOUND TO ANOTHER OBJECT? Yes, though T* const does equally well. Either is mainly useful as a local variable. (See also previousanswer.)
ISN’T T& CONVENIENT FOR EASILY EXPRESSING A POINTER THAT IS NOTNULL?
Not exactly — T& lets you express a pointer that’s not-null _and_ that can’t be rebound. You can also express not-null by using gsl::not_null<>(see
for example the Microsoft GSL implementation),
and one advantage of doing it this way is that it also lets you independently specify whether the pointer can be rebound or not — if you want it not to be rebindable, just add const as usual. WHAT ABOUT LAMBDA CAPTURE? is the right default for a lambda that’s passed to a function that will just use it and then return (aka structured lifetime) without storing it someplace where it will outlive the function call. Those structured uses fall under the umbrella of using references as parameter/return types. For non-parameter/return uses, prefer usingpointers.
WHAT ABOUT PAIRU; }?
I’ve mainly seen these come up as parameter and return types, where for the struct case the most common motivation is that C++ doesn’t (yet) support multiple return values, or as handwritten equivalents of what lambda capture does. For those uses, they fall under the umbrella of using references as parameter/return types. For non-parameter/return uses, prefer using pointers. BUT WHAT ABOUT USING A REFERENCE FOR ((OTHER USE NOT AS A PARAMETER OR RETURN TYPE OR LOCAL VARIABLE))? DON’T. WOPR said it best, describing something like the game of trying to answer this class of question: “A strange game. The only winning move is not to play.” Don’t let yourself be baited into even trying to answer this kind of question. For example, if you’re writing a class template, just assume (or document) that it can’t be instantiated with reference types. The question itself is a will o’ the wisp, and to even try to answer it is to enter a swamp, because there won’t be a generalreasonable answer.
(DISCLAIMER: You, dear reader, may at this very moment be thinking of an ((other use)) for which you think you have a reasonable and correct answer. Whatever it is, it’s virtually certain that a significant fraction of other experts are at this very moment reading this and thinking of that ((other use)) with a different answer, and that you can each present technical arguments why the other is wrong. See optionalthose. Otherwise:
DON’T, see previous. People keep trying this, and we keep having to teach them not to try because it makes classes work in weird and/orunintended ways.
Pop quiz: Is struct X { int& i; }; copyable? If not, why not? If so,what does it do?
Basic answer: X is not copy assignable, because i cannot be modified to point at something else. But X is copy constructible, where i behaves just as if it were a pointer. Better answer: X behaves the same as if the member were int* const i; — so why not just write that if that’s what’s wanted? Writing a pointer is arguably simpler and clearer. … BUT WHAT ABOUT USING A REFERENCE TYPE AS AN EXPLICIT TEMPLATEARGUMENT?
DON’T, see above. Don’t be drawn into trying to answer when this could be valid or useful. Explicitly jamming a reference type into a template that didn’t deduce it and isn’t expecting it, such as calling std::some_algorithmSPECIALIZATION?
DON’T, see above. Don’t be drawn into trying to answer when this could be valid or useful. … BUT WAIT, NOT EVEN OPTIONAL, example
).
Those posts are what prompted me to write this post, expanding on private email I wrote to one of the authors. Merely knowing that the discussion has continued for so many years with no consensus is a big red flag that the question itself is flawed. And if you’re reading this and think you have answer, ask yourself whether in your answer optionalproblem.
* If the design embraces the pointer-ness of references (one level of indirection), then one set of use cases works and people with alias-like use cases get surprised. * If the design embraces the alias-ness of references (no indirection), then the other set of use cases works and people with pointer-like use cases get surprised. * If the design mixes them, then a variety of people get surprised increative ways.
Java object references encounter similar problems — everything is implicitly a pointer, but there’s no clean way to syntactically distinguish the pointer vs. the pointee. Being able to talk separately about the pointer vs. the pointee is an important distinction, and an important and underestimated advantage of the Pointer-like things (e.g., raw pointers, iterators, ranges, views, spans) we have in C++. Herb Sutter Uncategorized18 Comments
2020-02-232020-02-2513 Minutes
MOVE, SIMPLY
_C++ “move” semantics are simple, and unchanged since C++11. But they are still widely misunderstood, sometimes because of unclear teaching and sometimes because of a desire to view move as something else instead of what it is. This post is an attempt to shed light on that situation._ _Thank you to the following for their feedback on drafts of this material: Howard Hinnant (lead designer and author of move semantics), Jens Maurer, Arthur O’Dwyer, Geoffrey Romer, Bjarne Stroustrup, Andrew Sutton, Ville Voutilainen, Jonathan Wakely._ _Edited to add: Formatting, added link, and reinstated a “stateful type” Q&A since the question was asked in comments._ MOVE: WHAT IT IS, AND HOW TO USE IT IN C++, COPYING OR MOVING FROM AN OBJECT A TO AN OBJECT B SETS B TO A’S ORIGINAL VALUE. THE ONLY DIFFERENCE IS THAT COPYING FROM A WON’T CHANGE A, BUT MOVING FROM A MIGHT. TO PASS A NAMED OBJECT A AS AN ARGUMENT TO A && “MOVE” PARAMETER (RVALUE REFERENCE PARAMETER), WRITE STD::MOVE(A). THAT’S PRETTY MUCH THE ONLY TIME YOU SHOULD WRITE STD::MOVE, BECAUSE C++ ALREADY USES MOVE AUTOMATICALLY WHEN COPYING FROM AN OBJECT IT KNOWS WILL NEVER BE USED AGAIN, SUCH AS A TEMPORARY OBJECT OR A LOCAL VARIABLE BEING RETURNED OR THROWN FROM A FUNCTION.THAT’S IT.
ADVANCED NOTES FOR TYPE AUTHORS Copying is a const operation on a, so copy construction/assignment functions should always take their parameter by const&. Move is a noexceptnon-const operation on a, so move construction/assignment functions should always be noexcept and take their parameter by(non-const) &&.
For copyable types, move is always an optimization of copy, so only explicitly write move functions for the type if copying is expensive enough to be worth optimizing. Otherwise, you’ll either get the implicitly generated move functions, or else requests to move will automatically just do a copy instead, since copy is always a valid implementation of move (it just doesn’t exercise thenon-const option).
For types that are move-only (not copyable), move is C++’s closest current approximation to expressing an object that can be cheaply moved around to different memory addresses, by making at least its value cheap to move around. (Other not-yet-standard proposals to go further in this direction include ones with names like “relocatable” and “destructive move,” but those aren’t standard yet so it’s premature to talk about them.) These types are used to express objects that have unique values or uniquely own aresource.
That’s it for what advanced users need to know. ------------------------- -------------------------APPENDIX: Q&A
WAIT, THAT SEEMS OVERSIMPLIFIED… FOR EXAMPLE, DOESN’T C++ LET ME WRITE COPY FUNCTIONS IN WAYS NOT MENTIONED ABOVE, LIKE WRITE A COPY CONSTRUCTOR THAT TAKES BY NON-CONST REFERENCE OR A MOVE CONSTRUCTORTHAT CAN THROW?
Yes, but don’t. Such things are legal but not good — ask auto_ptr (now removed), or vector implementations that used dynamic sentinel nodes (now being removed). HOW CAN MOVING FROM AN OBJECT NOT CHANGE ITS STATE? For example, moving an int doesn’t change the source’s value because an int is cheap to copy, so move just does the same thing as copy. Copy is always a valid implementation of move if the type didn’t provide anything more efficient. CAN A GIVEN TYPE DOCUMENT THAT MOVING FROM AN OBJECT ALWAYS CHANGES ITS STATE? OR CHANGES IT TO A KNOWN STATE? Yes, move is just another non-const function. Any non-const function can document when and how it changes the object’s state, including to specify a known new state as a postcondition if it wants. For example, unique_ptr‘s .release() function is guaranteed to set the object to null — just as its move functions are guaranteed to set the source object to null. I WROTE STD::MOVE(A) BUT A‘S VALUE DIDN’T CHANGE. WHY? Because moving from an object a can modify its value, but doesn’t have to. This is the same as any other non-const operation on a. There are other secondary reasons, but they’re all just special cases of the above fundamental reason, which applies irrespective of whether move is just a “move it if you can/want” cast or not, or whether a move vs. copy function is actually called, or othersecondary reasons.
BUT WHAT ABOUT THE “MOVED-FROM” STATE, ISN’T IT SPECIAL SOMEHOW? No. The state of a after it has been moved from is the same as the state of a after any other non-const operation. Move is just another non-constfunction that might (or might not) change the value of the source object. I HEARD THAT A MOVED-FROM OBJECT IS IN A STATE WHERE “YOU CAN CALL ITS FUNCTIONS THAT HAVE NO PRECONDITIONS,” OR IS IN A “VALID BUT UNSPECIFIED STATE,” IS THAT RIGHT? Yes, both are saying the same thing as above — the object continues to be a valid object of its type, its value might or might not have been modified. The standard library specifies this guarantee for all standard types, and all well-behaved types should do the same. Note that this is the same state as in the following example that’s familiar to C++ programmers of all experience levels:1
2
3
4
5
6
7
void f( /* and optionally const */ Thing& thing ) { // nopreconditions
// here 'thing' is a valid object of its type // (aka "in a valid but unspecified state") // ... naturally you’ll want to know its value, so now justask it,
// easy peasy, just use the object ...}
This is not a mysterious state. It’s the ordinary state any object is in when you first encounter it. DOES “BUT UNSPECIFIED” MEAN THE OBJECT’S INVARIANTS MIGHT NOTHOLD?
No. In C++, an object is valid (meets its invariants) for its entire lifetime, which is from the end of its construction to the start of its destruction (see /4 ). Moving from an object does not end its lifetime, only destruction does, so moving from an object does not make it invalid or not obey its invariants. If any non-const function on an object (including moving from it) makes the object invalid, the function has a bug. DON’T SOME STANDARD TYPES USE TWO-PHASE CONSTRUCTION WHERE A DEFAULT-CONSTRUCTED OBJECT ISN’T IN A VALID STATE, SUCH AS UNIQUE_PTR WHERE IF IT’S NULL YOU CAN ONLY USE A SUBSET OF ITS INTERFACE WITH DEFINED BEHAVIOR? AND MOVE-FROM PUTS THEM IN SUCH ANINVALID STATE?
No, and those aren’t two-phase construction types, they’re just stateful types and move-from puts them into one of their valid states. A two-phase construction type is typically written because people are using a non-standard C++ dialect that doesn’t have exceptions to report constructor errors, so the user has to first default-construct into a not-valid (“not-fully-formed” and not yet usable) state and then additionally call a named function (which can report errors in some non-exception way) to “construct the rest of the way” before actually using the object. After that, the default-constructed state of such types is typically one you can’t get back to later via other member functions; it’s not one of the valid states, it’s an artifact. This is not recommended when using Standard C++. None of the standard types are like that. All standard library types keep their objects in a valid usable state during their lifetimes. If they’re default constructible, the default constructor puts them into one of their valid states. DOES “BUT UNSPECIFIED” MEAN THE ONLY SAFE OPERATION ON A MOVED-FROM OBJECT IS TO CALL ITS DESTRUCTOR?No.
DOES “BUT UNSPECIFIED” MEAN THE ONLY SAFE OPERATION ON A MOVED-FROM OBJECT IS TO CALL ITS DESTRUCTOR OR TO ASSIGN IT A NEWVALUE?
No.
DOES “BUT UNSPECIFIED” SOUND SCARY OR CONFUSING TO AVERAGEPROGRAMMERS?
It shouldn’t, it’s just a reminder that the value might have changed, that’s all. It isn’t intended to make “moved-from” seem mysterious (it’s not). WHAT ABOUT OBJECTS THAT AREN’T SAFE TO BE USED NORMALLY AFTER BEINGMOVED FROM?
They are buggy. Here’s a recent example:1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Buggy class: Move leaves behind a null smart pointerclass IndirectInt {
shared_ptrpublic:
// ... more functions, but using defaulted move functions bool operator<(const IndirectInt& rhs) const { return *sp <*rhs.sp; }
//
oops: unconditional deref// ...
};
IndirectInt i;
i = move(i); // move leaves i.sp == nullptr sort(begin(i), end(i)); // undefined behavior This is simply a buggy movable type: The default compiler-generated move can leave behind a null sp member, but operator< unconditionally dereferences sp without checking for null. There are two possibilities: * If operator< is right and sp is supposed to never be null, then the class has a bug in its move functions and needs to fix that by suppressing or overriding the defaulted move functions. * Otherwise, if the move operation is right and sp is supposed to be nullable, then operator< has a bug and needs to fix it by checking for null before dereferencing. Either way, the class has a bug — the move functions and operator< can’t both be right, so one has to be fixed, it’sthat simple.
Assuming the invariant is intended to be that sp is not null, the ideal way to fix the bug is to directly express the design intent so that the class is correct by construction. Since the problem is that we are not expressing the “not null” invariant, we should express that by construction — one way is to make the pointer membera gsl::not_null<>
(see
for example the Microsoft GSL implementation)
which is copyable but not movable or default-constructible. Then the class is both correct by construction and simple to write:1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Corrected class: Declare intent, naturally get only copy and notmove
struct IndirectInt { not_nullpublic:
// ... more functions, but NOT using defaulted move functions // which are automatically suppressed bool operator<(const IndirectInt& rhs) const { return *sp <*rhs.sp; } // ok
// ...
};
IndirectInt i;
i = move(i); // performs a copy sort(begin(i), end(i)); // ok, no undefined behavior There’s one more question before we leave this example… BUT WHAT ABOUT A THIRD OPTION, THAT THE CLASS INTENDS (AND DOCUMENTS) THAT YOU JUST SHOULDN’T CALL OPERATOR< ON A MOVED-FROM OBJECT… THAT’S A HARD-TO-USE CLASS, BUT THAT DOESN’T NECESSARILY MAKE IT A BUGGY CLASS, DOES IT? Yes, in my view it does make it a buggy class that shouldn’t pass code review. The fundamental point is that “moved-from” really is just another ordinary state that can be encountered anytime, and so the suggested strategy would mean every user would have to test every object they ever encounter before they compare it… which is madness. But let’s try it out: In this most generous view of IndirectInt, let’s say that the class tries to boldly document to its heroic users that they must never try to compare moved-from objects. That’s not enough, because users won’t always know if a given object they encounter is moved-from. For example:1
2
3
4
void f(const IndirectInt& a, const IndirectInt& b) { if (a < b) // this would be a bug without first testing (somehow) that a and b both aren't moved-from// ...
}
Worse, it can be viral: For example, if we compose this type in a class X { Y y; IndirectInt value; Z z; /* ... */ }; and then make a vectorEOP)?
Not quite.
In EoP, the description of an object’s state as “partially formed but not well formed” is similar to the C++ Standard’s description of “valid but unspecified.” The difference is that EoP requires such objects to be assignable and destroyable (i.e., partially formed) while the C++ standard makes a broader statement that “operations on the object behave as specified for its type” and that a moved-from object “must still meet the requirements of the library component that is using it.” (See Cpp17MoveConstructible and Cpp17MoveAssignable.)
Herb Sutter Uncategorized57 Comments
2020-02-172020-02-219 Minutes
TRIP REPORT: WINTER ISO C++ STANDARDS MEETING (PRAGUE) A few minutes ago, the ISO C++ committee completed its final meeting of C++20 in Prague, Czech Republic. Our host, AVAST SOFTWARE, arranged for spacious and high-quality facilities for our six-day meeting from Monday through Saturday. The extra space was welcome, because we had a new record of 252 attendees. We currently have 23 active subgroups, and met in nine parallel tracks all week long; some groups ran all week, and others ran for a few days or a part of a day, depending ontheir workloads.
See also the Reddit trip report,
which was collaboratively edited by many committee members and has lots of excellent detail. You can find a brief summary of ISOprocedures here .
ISO
C++ committee in Prague, on the occasion of completing C++20 (February2020)
C++20 IS DONE!
Per our published C++20 schedule , we finished technical work on C++20 at this meeting. No features were added or removed, we just handled fit-and-finish issues including addressing all of the 378 national body comments we received in last summer’s international comment ballot (Committee Draft, or CD). The next step is that the final document will be sent out for its international approval ballot (Draft International Standard, or DIS) and will be published later this year. In addition to C++20 work, we also had time to make progress on a number of post-C++20 proposals, including continued work on contracts, networking, executors, reflection, compile-time programming, pattern matching, and much more. We also discussed ABI stability and took polls that said we are definitely not willing to guarantee pure ABI stability forever, and we are ready to consider proposals (especially ones that enable performance improvements) even if they may require an ABI break or migration on some platforms for affected types and functions, but that we aren’t ready to take a broad ABI break across the entire standard library. This is an important and meaningful decision, and an engraved invitation for proposal authors to bring proposals (and to bring back previously rejected ones) for their “wish lists” of such potentially-affected features, as soon as our next meeting this June. I’m looking forward very much to seeing how this can spur further C++ standard library innovation for C++23. Speaking of C++23… C++23 SCHEDULE AND PRIORITIES For the first time, we formally adopted a schedule and a planned set of feature priorities for the next round of standardization, C++23, right at its outset. The schedule for C++23 reaffirms that we’ll use the same meeting and feature-freeze deadline schedule that we used for C++20. Note that this means we are “only” two years away from the feature freeze of the next standard! Two years has a way of going by really quickly – “warning: objects in the schedule are closer than they appear.” The priorities for C++23’s feature set are to focus our work on the following, emphasizing upgrades to thestandard library:
* “Finishing C++20” with STANDARD LIBRARY MODULES and LIBRARY SUPPORT FOR COROUTINES. This will let programmers use the standard library via modules, and easily use coroutines with futures and other common types right “out of the box” (today some additional coding or a helper library is required). * Adding EXECUTORS and the NETWORKING LIBRARY that relies onexecutors.
On the language side, we will prioritize progressing the following as quickly as possible, for C++23 “if possible” but we’ll know better in a year or two whether they are likely to make it for 23 ornot:
* REFLECTION, including introspection to query the program, compile-time programming to manipulate the results, and generation to inject new entities into the program. * PATTERN MATCHING, which also progressed at this meeting with continued feedback on proposals. * CONTRACTS, which we spent another half-day on in SG21 on Fridayafternoon.
As a second priority, the wording groups will also prioritize bug fixing higher than in the past, to pay down technical debt faster. There will also be plenty of work on other features, so do expect C++23 to contain other work too. The purpose of setting these priorities is to mainly to say that at any given meeting we are not going to spend a lot of time working on other proposals until we have made as much progress as possible on the above ones first, that’s all. This way at each meeting we will give these proposals’ authors the maximum help and direction we can, so they can get as much further work done in the gap until the next meeting. Finally, note that “priorities” doesn’t mean “commitments.” Prioritizing these features is not a commitment that they’ll all be done in time for C++23, though we hope that most of them may likely be. Watch the next two years’ trip reports and you’ll get a good sense of how we’re making progress against these priorities.WRAPPING UP
Thank you again to the 252 experts who attended this final meeting of C++20, and the many more who participate in standardization through their national bodies! But we’re not slowing down… in less than four months we’ll be meeting again in Varna, Bulgaria, for the first meeting to start adopting features for C++23. I look forward to seeing many of you there. Thank you again to them and to everyone reading this for your interest and support for C++ and its standardization.NOTES
For those who are interested in my metaclasses proposal, this is ~98% of metaclasses – as soon as this reflection work lands, the only thing that will be left for me to propose to complete metaclasses is to add a declaration syntax like _class(M)_ as “just” a minor syntactic sugar for invoking a _consteval_ function that takes a _meta::info_ reflection of the class body as input. Herb Sutter Uncategorized7 Comments
2020-02-152020-02-154 Minutes
LAST NIGHT’S TALK VIDEO IS ONLINE: QUANTIFYING C++’S ACCIDENTAL COMPLEXITY, AND WHAT WE REALLY CAN DO ABOUT IT The ISO C++ committee is here in Prague this week to finish C++20, and the meeting hosts AVAST SOFTWARE also arranged a great C++ meetup last night where over 300 people came out to see BJARNE STROUSTRUP, TONY VAN EERD, AND ME give talks. The videos are already online, see below — they’re really high quality, and it was a great event. Thank you again to everyone who came out to see us! You made us feel very welcome in your beautiful city and your enthusiasm for C++ is contagious (in a good way!). Mine was a brand-new talk with material I’ve never presented on-camera before. (I gave a beta version at ACCU Autumn last November in Belfast.) I’m really excited about this upcoming work that I’m planning to bring to the committee in the near future, and I hope youenjoy it.
Thanks again to HANA DUSÍKOVÁ for her hard work organizing this meetup and this entire week-long record-shattering C++ standards meeting, by far the largest in history with 250 attendees. But there’s no rest for the competent — she still has to chair SG7 (reflection and compile-time programming) all day tomorrow. :) I’llbe there!
Herb Sutter Uncategorized10 Comments
2020-02-122020-03-091 Minute
TRIP REPORT: AUTUMN ISO C++ STANDARDS MEETING (BELFAST) A few minutes ago, the ISO C++ committee completed its autumn meeting in Belfast, Northern Ireland, hosted with thanks by clearpool.io, Archer-Yates, Microsoft, C++ Alliance, MCS Group, Instil, and the Standard C++ Foundation. As usual, we met for six days Monday through Saturday, and we had about 200 attendees. We now have 23 active subgroups, most of which met in nine parallel tracks all week long; some groups ran all week, and others ran for a few days or a part of a day, depending on their workloads. See also the Reddit trip report,
which was collaboratively edited by many committee members and has lots of excellent detail. You can find a brief summary of ISOprocedures here .
C++20 IS ON SCHEDULE TO BE FINALIZED IN FEBRUARY Per our official C++20 schedule , at our previous meeting in July we reached feature-freeze for C++20 and sent out the C++20 draft for its international comment ballot (Committee Draft, or CD) which ran over the summer and generated 378 comments from national bodies. At this meeting and the next one (February in Prague), our main job was to work through these comments as well as other fit-and-finish work for C++20. To make sure we were in good shape to finish in Prague, our goal was to make sure we resolved at least half the national body comments at this meeting. Thanks to a lot of hard work across all the subgroups, and especially the subgroup chairs who leveraged our ability to do work in parallel in our nine tracks and domain-specific subgroups, this week we resolved 73% of the national body comments, and made good progress on most of the rest. Here’s a snapshot of national body comment status, breaking out the number that we were able to close even before the end of the week, and the number of CWG (core language) and LWG (standard library) comments whose final resolutions we adopted today: This means we are in good shape to ship the final text of the C++20 standard at high quality and on time, at the end of the next meeting in February in Prague. Because we are in feature freeze for C++20, no new major proposals were added into C++20 at this meeting, though we did adopt a few minor design fixes. Most of the changes made at this meeting were bug-fix level improvements, mostly to the “wording implementation details” to make sure features were specified correctly and clearly in the formal specification wording to implement the approved design.OTHER PROGRESS
In addition to C++20 work, we also had time to make progress on a number of post-C++20 proposals, including: * the new SG21 (CONTRACTS) study group’s first meeting; * the newly reopened SG4 (NETWORKING) study group including an evening session on networking security; * an evening session on EXECUTORS; * further progress on REFLECTION and COMPILE-TIME PROGRAMMINGproposals;
* progress on PATTERN MATCHING in the main language evolution designgroup;
* and much more.
Thank you again to the approximately 200 experts who attended this meeting, and the many more who participate in standardization through their national bodies! Our next step is to finish the final text of C++20 three months from now in February (Prague, Czech Republic) and then send final C++20 out for its approval ballot. Herb Sutter Uncategorized6 Comments
2019-11-092019-11-092 Minutes
GOTW-ISH SOLUTION: THE ‘CLONABLE’ PATTERN This is the solution to GotW-ish: The ‘clonable’ pattern.
In summary, a distinguished C++ ISO C++ committee expert emailed me toask:
> , for each derived class, write> something like
>
> class D: public B {> public:
> shared_ptr clone() const { > return make_shared> }
> // ...
> };
>
> and then I can write>
> shared_ptr b1 = /* as before */; > shared_ptr b2 = b1->clone();>
> and b2 will now point to a shared_ptr that is bound to an object > with the same dynamic type as *b1.>
> However, this technique requires me to insert a member function into > every class derived from B, with ugly bugs resulting from failure to> do so.
>
> So my question is whether there some way of accomplishing this > automatically that I’ve missed? Let’s take a look.JG QUESTION
> * Describe as many approaches as you can think of that could let > us semi- or fully-automate this pattern, over just writing it by > hand every time as recommended in C++ Core Guidelines #C.130> .
> What are each approach’s advantages and drawbacks? There are two basic approaches in today’s C++: the Curiously Recurring Template Pattern (a.k.a. "CRTP"), and macros (a.k.a. "ick"). But first let’s consider a class of alternatives that is similar, even though it doesn’t answer this specific question or achieve thebasic goal.
NONINTRUSIVE SOLUTIONS There are nonintrusive solutions such as using type erasure, which don’t require the class to actually have a clone function. One example currently in the standardization proposal pipeline is P0201: A polymorphic value-type for C++ . P0201 leadsto code like this:
// The class hierarchy is unaffectedclass B {
};
class C : public B {};
class D : public C {};
// Wrappers enable writing code that's similar to the question... polymorphic_value b1(D()); // similar to the target use case polymorphic_value b2 = poly; The nonintrusive approaches are interesting too, but they don’t satisfy this particular question about how to automate the intrusive clone pattern. They also generally don’t satisfy the original motivation of the question which was to prevent slicing, because with nonintrusive approaches users can still create objects of the types directly and slice them:D d;
B b = d; // oops, still works Only an intrusive solution can make the copy constructor nonpublic or suppressed as part of automating the clone pattern, and all of the intrusive solutions can be extended to do this, with varying degrees of robustness and usability. So, how can we automate the pattern in the question? CRTP: THE CURIOUSLY RECURRING TEMPLATE PATTERN Since C++98, the main recommended method is to use a variation of CRTP, the Curiously Recurring Template Pattern.
The idea is that we instantiate a base class with our own type, and the base class provides the boilerplate we want. CRTP leads to code like this (live example — note that all the live examples use reflection to show the code that getsgenerated):
// User code: using the library to write our own types (many times) class B : public clonable_base {};
class C : public clonable {};
class D : public clonable {};
shared_ptr b1 = make_sharedpublic:
virtual std::unique_ptr}
};
templatepublic:
std::unique_ptr}
};
Advantages include:
* It’s standard C++: Works on all compilers. * It semi-automates the pattern. * It’s extensible: It can be directly extended to requirenonpublic copying.
Drawbacks include:
* It’s incomplete and repetitive: It requires cooperation from the code that uses it to supply the right types. It also violates the DRY principle (don’t repeat yourself). If we have to repeat the types, we can get them wrong, and I did make that mistake while writing thesamples.
* It makes it harder to diagnose mistakes: If the supplied types are wrong, the error messages can be subtle. For example, as I was writing the live example, sometimes I wrote the template arguments incorrectly (because cut-and-paste), and it took me longer than I’d like to admit to diagnose the bug because the error message was related to the static_cast downcast inside the clonable implementation which wasn’tthe root cause.
MACROS
And there are, well, macros. They lead to code like this (live example):
// User code: using the macros to write our own types (many times)class B {
CLONABLE_BASE(B);
};
class C : public B {CLONABLE(B);
};
class D : public C {CLONABLE(B);
};
shared_ptr b1 = make_shared}
#define CLONABLE(Base) \ std::unique_ptr}
Advantages include:
* It’s standard C++: Works on all compilers. * It semi-automates the pattern: Though less so than CRTP did. * It’s extensible: It can be directly extended to requirenonpublic copying.
* It’s easier than CRTP to diagnose mistakes, if you have a modern compiler: If the supplied types are wrong, the error messages are more obvious, at least with a compiler that has good diagnostics formacros.
Drawbacks include:
* It’s brittle: Macros are outside the language and can also alter other code in the same file. We hates macroses. Sneaky little macroses. Wicked. Tricksy. False. * It’s incomplete and repetitive: Like CRTP, we have to supply information and repeat things, but a little less than with CRTP.SUMMARY SO FAR
You can find more examples and variations of these proposed by a number of people on the original post’s commentsand
on the Reddit thread.
Both CRTP and macros have drawbacks. And perhaps the most fundamental is this point from the original question (emphasis added): > However, requires me to insert a member > function into every class derived from B, WITH UGLY BUGS RESULTING > FROM FAILURE TO DO SO.Can we do better?
GURU QUESTION
> * Show a working Godbolt.org link that shows how class authors can > write as close as possible to this code with the minimum possible > additional boilerplate code:>
> class B {
> };
>
> class C : public B {> };
>
> class D : public C {> };
>
> and that still permits the class’ users to write exactly the> following:
>
> shared_ptr b1 = make_sharedare to express:
* Requirements: We can check for mistakes in the users’ code, and report them with clean and readable compile-time diagnostics. * Defaults: We can apply defaults, such as to make member functionspublic by default.
* Generated functions: We can generate functions, such as clone. Let’s start with a simple direct example that does just answers the immediate question, and leads to code like this live example):
// User code: using the library to write our own types (many times) class(clonable) B {};
class(clonable) C : public B {};
class(clonable) D : public C {};
shared_ptr b1 = make_shared}
}
}
// Apply generated function: provide polymorphic clone() function using computed clone_type if (base_has_clone) { // then inject a virtual overrider -> __fragment struct Z { typename(clone_type) clone() const override { return std::unique_ptr}
};
}
else { // else inject a new virtual function -> __fragment struct Z { virtual std::unique_ptr}
};
}
};
Advantages include:
* It fully automates the pattern. * It’s extensible: It can be directly extended to require nonpublic copying. (See next section.) * It’s complete and nonrepetitive: The code that uses clonable only has to say that one word. It doesn’t have to supply the right types or repeat names; reflection lets the metafunction discover and compute exactly what it needs, accurately every time. * It’s easy to diagnose mistakes: We can’t make the mistakes we made with CRTP and macros, plus we get as many additional new high-quality diagnostics we might want. In this example, we already get a clear compile-time error if we create a class hierarchy that introduces clone() twice with two different types.Drawbacks include:
* It’s not yet standard C++: The reflection proposals are progressing not but yet ready to be adopted. BUT WAIT… ALL OF THE SOLUTIONS SO FAR ARE FLAWED It turns out that by focusing on clone and showing empty-class examples, we have missed a set of usability and correctness problems. Fortunately, we will solve those too in just a moment. Consider this slightly more complete example of the above code to show what it’s like to write a non-empty class, and a print test function that lets us make sure we really are doing a deep clone: class(clonable) B {public:
virtual void print() const { std::cout << "B"; }private:
int bdata;
};
class(clonable) C : public B {public:
void print() const override { std::cout << "C"; }private:
int cdata;
};
class(clonable) D : public C {public:
void print() const override { std::cout << "D"; }private:
int ddata;
};
This "works" fine. But did you notice it has pitfalls? Take a moment to think about it: If you encountered this code in a code review, would you approve it? ------------------------- OK, for starters, all of these classes are polymorphic, but all of them have _public non-virtual_ destructors and _public_ copy constructors and copy assignment operators. That’s not good. Remember one of the problems of a nonintrusive solution was that it doesn’t actually prevent slicing because you can still write this:D d;
B b = d; // oops, still works So what we should actually be writing using all of the solutions so far is something like this: class(clonable) B {public:
virtual void print() const { std::cout << "B"; } virtual ~B() noexcept { }B() = default;
protected:
B(const B &) = default; B& operator=(const B&) = delete;private:
int bdata;
};
class(clonable) C : public B {public:
void print() const override { std::cout << "C"; } ~C() noexcept override { }C() = default;
protected:
C(const C &) = default; C& operator=(const C&) = delete;private:
int cdata;
};
class(clonable) D : public C {public:
void print() const override { std::cout << "D"; } ~D() noexcept override { }D() = default;
protected:
D(const D &) = default; D& operator=(const D&) = delete;private:
int ddata;
};
That’s a lot of boilerplate. In fact, it turns out that even though the original question was about the boilerplate code of the clone function, MOST OF THE BOILERPLATE IS IN OTHER FUNCTIONS ASSUMED AND NEEDED BY CLONE PATTERN that weren’t even mentioned in the original question, but come up as soon as you try to use the proposed patterns in even simple real code. METACLASSES: FULLER "REAL" SOLUTION Fortunately, as I hinted above, we can do even better. The metaclass function can take care of all of this for us: * Apply default accessibilities and qualifiers: Make base classes and member functions public by default, data members private by default, and the destructor virtual by default. * Apply requirements: Check and enforce that a polymorphic type doesn’t have a public copy/move constructor, doesn’t have assignment operators, and that the destructor is either public and virtual or protected and nonvirtual. Note that these are accurate _compile-time_ errors, the best kind. * Generate functions: Generate a public virtual destructor if the user doesn’t provide one. Generate a protected copy constructor if the user doesn’t provide one. Generate a default constructor if all bases and members are default constructible. Now the same user code is: * Simple and clean. As far as I can tell, it literally could not be significantly shorter — we have encapsulated a whole set of opt-in defaults, requirements, and generated functions under the single word "clonable" library name that a class author can opt into by uttering that single Word of Power. * Correct by default. * Great error messages if the user writes a mistake.Live example
class(clonable) B { virtual void print() const { std::cout << "B"; }int bdata;
};
class(clonable) C : B { void print() const override { std::cout << "C"; }int cdata;
};
class(clonable) D : C { void print() const override { std::cout << "D"; }int ddata;
};
That’s it. (And, I’ll add: _This_ is "simplifying C++.")How did we do it?
In my consteval library, I added the following polymorphic metaclass function, which is invoked by clonable (i.e., a clonable is-a polymorphic). I made it a separate function for just the usual good code factoring reasons: polymorphic offers nicely reusable behavior even for non-clonable types. Here is the code, in addition to the above cloneable which adds the computed clone at the end — and remember, we only need to write the following library code _once_, and then class authors can enjoy the above simplicity forever: // Library code: implementing the metaclass functions (once) consteval void polymorphic(meta::info source) { using namespace meta; // For each base class... bool base_has_virtual_dtor = false; for (auto mem : base_spec_range(source)) { // Remember whether we found a virtual destructor in a base class for (auto base_mem : member_fn_range(mem)) if (is_destructor(base_mem) && is_virtual(base_mem)) { base_has_virtual_dtor = true;break;
}
// Apply default: base classes are public by default if (has_default_access(mem))make_public(mem);
// And inject it
-> mem;
}
// For each data member... for (auto mem : data_member_range(source)) { // Apply default: data is private by default if (has_default_access(mem))make_private(mem);
// Apply requirement: and the programmer must not have made it explicitly public compiler.require(!is_public(mem), "polymorphic classes' data members must be nonpublic");// And inject it
-> mem;
}
// Remember whether the user declared these SMFs we will otherwise generate bool has_dtor = false; bool has_default_ctor = false; bool has_copy_ctor = false; // For each member function... for (auto mem : member_fn_range(source)) { has_default_ctor |= is_default_constructor(mem); // If this is a copy or move constructor... if ((has_copy_ctor |= is_copy_constructor(mem)) || is_move_constructor(mem)) { // Apply default: copy/move construction is protected by default in polymorphic types if (has_default_access(mem)) make_protected(mem); // Apply requirement: and the programmer must not have made it explicitly public compiler.require(!is_public(mem), "polymorphic classes' copy/move constructors must be nonpublic");}
// Apply requirement: polymorphic types must not have assignment compiler.require(!is_copy_assignment_operator(mem) && !is_move_assignment_operator(mem), "polymorphic classes must not have assignment operators"); // Apply default: other functions are public by default if (has_default_access(mem))make_public(mem);
// Apply requirement: polymorphic class destructors must be // either public and virtual, or protected and nonvirtual if (is_destructor(mem)) {has_dtor = true;
compiler.require((is_protected(mem) && !is_virtual(mem)) || (is_public(mem) && is_virtual(mem)), "polymorphic classes' destructors must be public and virtual, or protected and nonvirtual");}
// And inject it
-> mem;
}
// Apply generated function: provide default for destructor if the user did notif (!has_dtor) {
if (base_has_virtual_dtor) -> __fragment class Z { public: ~Z() noexcept override { } };else
-> __fragment class Z { public: virtual ~Z() noexcept { } };}
// Apply generated function: provide defaults for constructors if the user did not if (!has_default_ctor) -> __fragment class Z { public: Z() =default; }; if (!has_copy_ctor) -> __fragment class Z { protected: Z(const Z&) =default; };}
Herb Sutter Uncategorized11 Comments
2019-10-032019-10-0512 Minutes
POSTS NAVIGATION
Older posts
Search for:
FOLLOW BY EMAIL
Subscribe
TWEETS
* RT @visualc : Announcing Pure Virtual C++ Conference 2020: a free single-track one-day virtual conference for the whole C++ community on Apr… 4 days ago * @incomputable Definitely not any-god, I'm still working on "human being." But re spaces: I write what feels most re… twitter.com/i/web/status/1…4 weeks ago
* RT @isocpp : We hope you all & your families are staying safe #TogetherAtHomeEach spring,
isocpp.org runs a short C++ develop…4 weeks ago
ARCHIVES
* March 2020 (1)
* February 2020 (4) * November 2019 (1) * October 2019 (1) * September 2019 (4)* July 2019 (5)
* June 2019 (1)
* May 2019 (1)
* April 2019 (1)
* February 2019 (1) * November 2018 (2) * September 2018 (3)* July 2018 (1)
* April 2018 (1)
* November 2017 (2) * October 2017 (3) * September 2017 (3)* July 2017 (2)
* June 2017 (1)
* March 2017 (1)
* February 2017 (2) * November 2016 (1) * September 2016 (4)* June 2016 (2)
* March 2016 (1)
* October 2015 (1) * September 2015 (1)* July 2015 (1)
* June 2015 (1)
* May 2015 (1)
* April 2015 (1)
* January 2015 (1) * December 2014 (1) * November 2014 (3) * October 2014 (2) * September 2014 (2)* August 2014 (1)
* July 2014 (2)
* May 2014 (3)
* April 2014 (4)
* March 2014 (4)
* February 2014 (2) * January 2014 (4) * December 2013 (4) * November 2013 (4) * October 2013 (2) * September 2013 (6)* August 2013 (5)
* July 2013 (1)
* June 2013 (7)
* May 2013 (22)
* April 2013 (2)
* March 2013 (1)
* February 2013 (1) * January 2013 (3) * December 2012 (3) * November 2012 (6) * October 2012 (5) * September 2012 (3)* August 2012 (3)
* July 2012 (1)
* June 2012 (7)
* May 2012 (5)
* April 2012 (17)
* March 2012 (4)
* February 2012 (5) * January 2012 (7) * December 2011 (3) * November 2011 (6) * October 2011 (10) * September 2011 (3)* August 2011 (3)
* July 2011 (2)
* June 2011 (4)
* May 2011 (5)
* April 2011 (3)
* March 2011 (2)
* January 2011 (1) * December 2010 (2) * October 2010 (5) * September 2010 (3)* August 2010 (2)
* July 2010 (1)
* June 2010 (2)
* May 2010 (5)
* April 2010 (5)
* March 2010 (9)
* February 2010 (2) * January 2010 (3) * December 2009 (1) * November 2009 (4) * October 2009 (6) * September 2009 (2)* August 2009 (2)
* July 2009 (2)
* June 2009 (3)
* May 2009 (4)
* April 2009 (2)
* March 2009 (4)
* February 2009 (3) * January 2009 (5) * December 2008 (4) * November 2008 (2) * October 2008 (3) * September 2008 (3)* August 2008 (4)
* July 2008 (6)
* June 2008 (6)
* May 2008 (2)
* April 2008 (6)
* March 2008 (5)
* February 2008 (1) * January 2008 (7) * December 2007 (5) * November 2007 (4) * October 2007 (1) * September 2007 (6)* August 2007 (6)
* July 2007 (6)
* June 2007 (3)
* May 2007 (3)
* April 2007 (2)
* March 2007 (3)
* February 2007 (3) * January 2007 (6) * December 2006 (2) Blog at WordPress.com.Sutter’s Mill
Blog at WordPress.com.Post to
Cancel
* Follow
*
* Sutter’s Mill
* Customize
* Follow
* Sign up
* Log in
* Report this content * Manage subscriptions* Collapse this bar
Details
Copyright © 2024 ArchiveBay.com. All rights reserved. Terms of Use | Privacy Policy | DMCA | 2021 | Feedback | Advertising | RSS 2.0