Or better still just use the type system and replace `Int` with `int32_t`.
##### Example
void read(int* p, int n); // read max n integers into *p
@ -1742,7 +1744,7 @@ If you can't use exceptions (e.g. because your code is full of old-style raw-poi
int val;
int error_code;
tie(val, error_code) = do_something();
if (error_code == 0) {
if (error_code) {
// ... handle the error or exit ...
}
// ... use val ...
@ -1751,7 +1753,7 @@ This style unfortunately leads to uninitialized variables.
A facility [structured bindings](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0144r1.pdf) to deal with that will become available in C++17.
auto [val, error_code] = do_something();
if (error_code == 0) {
if (error_code) {
// ... handle the error or exit ...
}
// ... use val ...
@ -2844,7 +2846,7 @@ For advanced uses (only), where you really need to optimize for rvalues passed t
Avoid "esoteric techniques" such as:
* Passing arguments as `T&&` "for efficiency".
Most rumors about performance advantages from passing by `&&` are false or brittle (but see [F.25](#Rf-pass-ref-move).)
Most rumors about performance advantages from passing by `&&` are false or brittle (but see [F.18](#Rf-consume) and [F.19](#Rf-forward)).
* Returning `const T&` from assignments and similar operations (see [F.47](#Rf-assignment-op).)
##### Example
@ -2889,7 +2891,7 @@ This makes it clear to callers that the object is assumed to be modified.
##### Note
A `T&` argument can pass information into a function as well as well as out of it.
A `T&` argument can pass information into a function as well as out of it.
Thus `T&` could be an in-out-parameter. That can in itself be a problem and a source of errors:
void f(string& s)
@ -3584,7 +3586,7 @@ Flag functions where no `return` expression could yield `nullptr`
##### Reason
It's asking to return a reference to a destroyed temporary object. A `&&` is a magnet for temporary objects. This is fine when the reference to the temporary is being passed "downward" to a callee, because the temporary is guaranteed to outlive the function call. (See [F.24](#Rf-pass-ref-ref) and [F.25](#Rf-pass-ref-move).) However, it's not fine when passing such a reference "upward" to a larger caller scope. See also ???.
It's asking to return a reference to a destroyed temporary object. A `&&` is a magnet for temporary objects. This is fine when the reference to the temporary is being passed "downward" to a callee, because the temporary is guaranteed to outlive the function call (see [F.18](#Rf-consume) and [F.19](#Rf-forward)). However, it's not fine when passing such a reference "upward" to a larger caller scope. See also ???.
For passthrough functions that pass in parameters (by ordinary reference or by perfect forwarding) and want to return values, use simple `auto` return type deduction (not `auto&&`).
@ -4173,7 +4175,7 @@ Prefer to place the interface first in a class [see](#Rl-order).
##### Enforcement
Flag classes declared with `struct` if there is a `private` or `public` member.
Flag classes declared with `struct` if there is a `private` or `protected` member.
### <aname="Rc-private"></a>C.9: Minimize exposure of members
@ -5637,7 +5639,7 @@ Types can be defined to move for logical as well as performance reasons.
##### Reason
It is simple and efficient. If you want to optimize for rvalues, provide an overload that takes a `&&` (see [F.24](#Rf-pass-ref-ref)).
It is simple and efficient. If you want to optimize for rvalues, provide an overload that takes a `&&` (see [F.18](#Rf-consume)).
##### Example
@ -5662,7 +5664,7 @@ It is simple and efficient. If you want to optimize for rvalues, provide an over
##### Note
The `swap` implementation technique offers the [strong guarantee](???).
The `swap` implementation technique offers the [strong guarantee](#Abrahams01).
##### Example
@ -5691,7 +5693,7 @@ But what if you can get significantly better performance by not making a tempora
return *this;
}
By writing directly to the target elements, we will get only [the basic guarantee](#???) rather than the strong guarantee offered by the `swap` technique. Beware of [self-assignment](#Rc-copy-self).
By writing directly to the target elements, we will get only [the basic guarantee](#Abrahams01) rather than the strong guarantee offered by the `swap` technique. Beware of [self-assignment](#Rc-copy-self).
**Alternatives**: If you think you need a `virtual` assignment operator, and understand why that's deeply problematic, don't call it `operator=`. Make it a named function like `virtual void assign(const Foo&)`.
See [copy constructor vs. `clone()`](#Rc-copy-virtual).
@ -5732,7 +5734,7 @@ After a copy `x` and `y` can be independent objects (value semantics, the way no
X::X(const X& a)
:p{new T[a.sz]}, sz{a.sz}
{
copy(a.p, a.p + sz, a.p);
copy(a.p, a.p + sz, p);
}
X x;
@ -5980,7 +5982,7 @@ A non-throwing move will be used more efficiently by standard-library and langua
int sz;
};
These copy operations do not throw.
These operations do not throw.
##### Example, bad
@ -6695,6 +6697,8 @@ Use `virtual` only when declaring a new virtual function. Use `override` only wh
@ -15157,7 +15184,7 @@ Consider `finally` a last resort.
##### Note
Use of `finally` is a systematic and reasonably clean alternative to the old [`goto exit;` technique](##Re-no-throw-codes)
Use of `finally` is a systematic and reasonably clean alternative to the old [`goto exit;` technique](#Re-no-throw-codes)
for dealing with cleanup where resource management is not systematic.
##### Enforcement
@ -18759,7 +18786,7 @@ Distinguishing these alternatives prevents misunderstandings and bugs.
All we know is that it is supposed to be the nullptr or point to at least one character
void f1(zstring s); // s is a C-style string or the nullptr
void f1(czstring s); // s is a C-style string that is not the nullptr
void f1(czstring s); // s is a C-style string constant or the nullptr
void f1(std::byte* s); // s is a pointer to a byte (C++17)
##### Note
@ -19299,7 +19326,7 @@ Many, possibly most, problems with exceptions stem from historical needs to inte
The fundamental arguments for the use of exceptions are
* They clearly separates error return from ordinary return
* They clearly differentiate between erroneous return and ordinary return
* They cannot be forgotten or ignored
* They can be used systematically
@ -20287,15 +20314,15 @@ In the context of C++, this style is often called "Stroustrup".
}
switch (x) {
case 0:
// ...
break;
case amazing:
// ...
break;
default:
// ...
break;
case 0:
// ...
break;
case amazing:
// ...
break;
default:
// ...
break;
}
if (0 <x)
@ -20759,7 +20786,7 @@ In this rare case, you could make the destructor public and nonvirtual but clear
In general, however, avoid concrete base classes (see Item 35). For example, `unary_function` is a bundle-of-typedefs that was never intended to be instantiated standalone. It really makes no sense to give it a public destructor; a better design would be to follow this Item's advice and give it a protected nonvirtual destructor.
### <aname="Sd-noexcept"></a>Discussion: Usage of noexcept
@ -20833,9 +20860,9 @@ These are key functions that must not fail because they are necessary for the tw
Consider the following advice and requirements found in the C++ Standard:
> If a destructor called during stack unwinding exits with an exception, terminate is called (15.5.1). So destructors should generally catch exceptions and not let them propagate out of the destructor. --[\[C++03\]](#C++03) §15.2(3)
> If a destructor called during stack unwinding exits with an exception, terminate is called (15.5.1). So destructors should generally catch exceptions and not let them propagate out of the destructor. --[\[C++03\]](#Cplusplus03) §15.2(3)
>
> No destructor operation defined in the C++ Standard Library (including the destructor of any type that is used to instantiate a standard-library template) will throw an exception. --[\[C++03\]](#C++03) §17.4.4.8(3)
> No destructor operation defined in the C++ Standard Library (including the destructor of any type that is used to instantiate a standard-library template) will throw an exception. --[\[C++03\]](#Cplusplus03) §17.4.4.8(3)
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`:
@ -20851,7 +20878,7 @@ Fortunately, when releasing a resource, the scope for failure is definitely smal
When using exceptions as your error handling mechanism, always document this behavior by declaring these functions `noexcept`. (See Item 75.)
## <aname="Sd-consistent"></a>Define Copy, move, and destroy consistently
@ -20937,7 +20964,7 @@ Prefer compiler-generated (including `=default`) special members; only these can
In rare cases, classes that have members of strange types (such as reference members) are an exception because they have peculiar copy semantics.
In a class holding a reference, you likely need to write the copy constructor and the assignment operator, but the default destructor already does the right thing. (Note that using a reference member is almost always wrong.)