@ -2576,16 +2576,16 @@ In fact, C++98's standard library already used this convenient feature, because
For example, given a `set<string> myset`, consider:
// C++98
result = myset.insert("Hello");
if (result.second) do_something_with(result.first); // workaround
result = myset.insert("Hello");
if (result.second) do_something_with(result.first); // workaround
With C++11 we can write this, putting the results directly in existing local variables:
Sometype iter; // default initialize if we haven't already
Someothertype success; // used these variables for some other purpose
tie(iter, success) = myset.insert("Hello"); // normal return value
if (success) do_something_with(iter);
tie(iter, success) = myset.insert("Hello"); // normal return value
if (success) do_something_with(iter);
**Exception**: For types like `string` and `vector` that carry additional capacity, it can sometimes be useful to treat it as in/out instead by using the "caller-allocated out" pattern, which is to pass an output-only object by reference to non-`const` so that when the callee writes to it the object can reuse any capacity or other resources that it already contains. This technique can dramatically reduce the number of allocations in a loop that repeatedly calls other functions to get string values, by using a single string object for the entire loop.
@ -2876,7 +2876,7 @@ Flag all uses of default arguments in virtual functions.
This is a simple three-stage parallel pipeline. Each `stage` object encapsulates a worker thread and a queue, has a `process` function to enqueue work, and in its destructor automatically blocks waiting for the queue to empty before ending the thread.
while ((cin>>c1, cin>>c2), c1==c2) // bad: two non-local variables assigned in a sub-expressions
for (char c1, c2; cin>>c1>>c2 && c1==c2;) // better, but possibly still too complicated
for (char c1, c2; cin>>c1>>c2 && c1==c2;) // better, but possibly still too complicated
int x = ++i + ++j; // OK: iff i and j are not aliased
@ -8792,7 +8792,7 @@ after an implementation bug caused losses to some finance company and they were
It should definitely mention that `volatile` does not provide atomicity, does not synchronize between threads, and does not prevent instruction reordering (neither compiler nor hardware), and simply has nothing to do with concurrency.
??? Is `std::async` worth using in light of future (and even existing, as libraries) parallelism facilities? What should the guidelines recommend if someone wants to parallelize, e.g., `std::accumulate` (with the additional precondition of commutativity), or merge sort?
@ -11908,21 +11908,21 @@ Reading from a vararg assumes that the correct type was actually passed. Passing
int sum(...) {
// ...
while(/*...*/)
while(/*...*/)
result += va_arg(list, int); // BAD, assumes it will be passed ints
// ...
}
sum(3, 2); // ok
sum(3.14159, 2.71828); // BAD, undefined
sum(3, 2); // ok
sum(3.14159, 2.71828); // BAD, undefined
template<class...Args>
auto sum(Args... args) { // GOOD, and much more flexible
Note: Declaring a `...` parameter is sometimes useful for techniques that don't involve actual argument passing, notably to declare “take-anything” functions so as to disable "everything else" in an overload set or express a catchall case in a template metaprogram.
@ -12522,7 +12522,7 @@ Impossible.
#include<map>
int main (int argc , char * argv [ ])
int main (int argc , char * argv [ ])
{
// ...
}
@ -13021,7 +13021,7 @@ Consider the following advice and requirements found in the C++ Standard:
Deallocation functions, including specifically overloaded `operator delete` and `operator delete[]`, fall into the same category, because they too are used during cleanup in general, and during exception handling in particular, to back out of partial work that needs to be undone.
Besides destructors and deallocation functions, common error-safety techniques rely also on `swap` operations never failing--in this case, not because they are used to implement a guaranteed rollback, but because they are used to implement a guaranteed commit. For example, here is an idiomatic implementation of `operator=` for a type `T` that performs copy construction followed by a call to a no-fail `swap`: