C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Relocation in C++

From: Thiago Macieira <thiago_at_[hidden]>
Date: Fri, 06 May 2022 23:03:37 -0700
On Thursday, 5 May 2022 18:37:42 PDT Edward Catmur via Std-Proposals wrote:
> In practical terms, what happens if we have a type T with user-defined
> destructor, and to release some resource ~T accesses members x and y, with
> x having throwing (move-plus-destroy) relocate?

If x's relocator throws, then when that exception is thrown, both source and
destination objects have no lifetime. The destination's has never started and
the source has irrevocably ended the moment the relocator started. There's no
going back.

That means:

> Suppose x's destructor
> throws after dst.x has been move-constructed from src.x;

This condition is not possible. The relocator is responsible for transferring
the lifetime. If it throws -- regardless of it did so explicitly or because a
function it called threw -- then dst.x is not constructed. Unwinding happens
and dst.x's lifetime rolls back.

> then there is no
> object of T (with members x and y both within their lifetime) that we can
> call ~T on, so the resource will leak.

Right. That's the same problem, just one level removed.

> This is unacceptable, so the only
> safe thing to do if an exception is thrown midway through a user-defined
> relocate is to terminate.

I agree it's unacceptable, but what's unacceptable is writing throwing moves
and throwing destructors. Whoever writes those is accepting pain.

Relocators, like destructors, should be by default noexcept(true). Making them
noexcept(false) should be an intentional and explicit choice. In turn, it
means that if the choice wasn't made, then calling a function that throws from
that relocator and failing to catch will cause std::terminate(), as you
proposed.

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel DPG Cloud Engineering

Received on 2022-05-07 06:03:39