Date: Thu, 06 Feb 2020 16:18:01 +0300
On 2019-10-27 04:18:49, Andrew Tomazos via Std-Proposals wrote:
> There are a number of types in the language that are optional-like. They
> are explicitly convertible to bool and answer to unary operator*. If the
> conversion to bool would result in false, it is UB to call operator* on
> them. Such types include at least pointers, std::unique_ptr,
> std::shared_ptr and std::optional. Beyond that there are a number of
> functions that return objects of such types (such as dynamic_cast,
> get_if, and many many others that use the false state to indicate
> failure). By providing a way to fuse a branch on the bool conversion
> with the dereference only in the safe (true) branch, we make the UB
> (from the false state + dereference) statically unreachable. (or at
> least harder to accidentally trigger)
>
> In short: it's a safety issue. Ask yourself what the potential problems
> are if the programmer made a typo in your PacketVariant example.
I totally agree with you.
With this proposal it is possible to write, for example:
1.
void process(const std::weak_ptr<Storage>& storage,
const std::weak_ptr<Value>& value)
{
if (auto& [storage, value] : lock(storage, value))
storage.insert(value);
else
do_else();
}
instead of:
2.
void process(const std::weak_ptr<Storage>& storage,
const std::weak_ptr<Value>& value)
{
if (auto locs = lock(storage, value))
{
auto& [storage, value] = locs;
storage.insert(value);
}
else
do_else();
}
Although this is just saving a few keystrokes, I prefer the first version,
because it is more convenient, clear, and safer, without an annoying
temporary variable. So I think this is a useful proposal.
> There are a number of types in the language that are optional-like. They
> are explicitly convertible to bool and answer to unary operator*. If the
> conversion to bool would result in false, it is UB to call operator* on
> them. Such types include at least pointers, std::unique_ptr,
> std::shared_ptr and std::optional. Beyond that there are a number of
> functions that return objects of such types (such as dynamic_cast,
> get_if, and many many others that use the false state to indicate
> failure). By providing a way to fuse a branch on the bool conversion
> with the dereference only in the safe (true) branch, we make the UB
> (from the false state + dereference) statically unreachable. (or at
> least harder to accidentally trigger)
>
> In short: it's a safety issue. Ask yourself what the potential problems
> are if the programmer made a typo in your PacketVariant example.
I totally agree with you.
With this proposal it is possible to write, for example:
1.
void process(const std::weak_ptr<Storage>& storage,
const std::weak_ptr<Value>& value)
{
if (auto& [storage, value] : lock(storage, value))
storage.insert(value);
else
do_else();
}
instead of:
2.
void process(const std::weak_ptr<Storage>& storage,
const std::weak_ptr<Value>& value)
{
if (auto locs = lock(storage, value))
{
auto& [storage, value] = locs;
storage.insert(value);
}
else
do_else();
}
Although this is just saving a few keystrokes, I prefer the first version,
because it is more convenient, clear, and safer, without an annoying
temporary variable. So I think this is a useful proposal.
-- Victor Kireev
Received on 2020-02-06 07:20:41