On Wed, 18 Jan 2023 at 18:53, Brian Bi <bbi5291@gmail.com> wrote:


On Wed, Jan 18, 2023 at 12:38 PM Edward Catmur via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
On Wed, 18 Jan 2023 at 17:18, Frank B. Brokken via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
Dear Edward Catmur, you wrote:
> On Wed, 18 Jan 2023 at 16:02, Frank B. Brokken via Std-Discussion <

> > ... reaches the constructor's function-try-block handler.
>
> This seems to me a simple corollary of [class.cdtor], particularly
> paragraph 1. I'd even question whether normative wording is necessary under
> [except.handle]; this could probably be a note.

Hi Edward,

Thanks for the fast reply to my question.

11.9.5 [class.cdtor] states:

    ... For an object with a non-trivial destructor, referring to any
    non-static member or base class of the object after the destructor
    finishes execution results in undefined behavior.

However, that's not the situation I'm encountering. In the example an
exception is thrown from the constructor's body and so no destructor is
called.

Ah, true; the destructor of the class is only called in case of a delegating constructor [except.ctor].

So either the class is not "under construction or destruction" and [basic.life]p6 applies (and is thus inconsistent with [except.ctor]), or [class.cdtor] is incomplete, or possibly both. This might be a defect.

First of all, I'm sorry I didn't notice your first reply to this thread before I wrote my reply.

Anyway, after having looked at [basic.life]/6, I don't see what the issue is. I think that [basic.life]/6 does not give license to do all the things that aren't specifically forbidden therein. If the class has a non-trivial constructor, then the restrictions in [class.cdtor]/1 apply in addition to the ones in [basic.life]/6.

Ah, you're right - I think I'm confused by reading "For an object under construction or destruction, see [class.cdtor]. Otherwise..." but having wording in [class.cdtor] (specifically, paragraph 1 thereof) apply also for objects not under construction or destruction. My apologies.

Also, "Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below." gives a false impression of being exhaustive when in fact, as you say, the restrictions of [class.cdtor]/1 apply as well.

So if a class has a virtual base, and thus a non-trivial constructor, [class.cdtor]/1 says we cannot refer to its members before construction begins, [basic.life]/6 notwithstanding; if it has a trivial destructor, however, we can refer to (but not access) those members after destruction finishes. If instead we end its lifetime through storage reuse (which could overwrite the vtable pointer, to put it crudely), [basic.life]/4 means we cannot refer to those members; [basic.life]/6 (etc.) does not apply once storage is reused. I think we're good here.

Going back to [except.handle]/10, this appears to complement [class.cdtor]/1, implying that within a constructor (or destructor) function-try-block, the class is still under construction (or destruction). Is it problematic that [class.cdtor] 5 and 6 (typeid and dynamic_cast) would appear to be allowed in such function-try-blocks? I suppose it's OK.


But before the exception is thrown its d_value has received a value,
which is then displayed in its function-try-block.

Well, yes, but you aren't allowed to access that value, both because that int object is outside its lifetime, and also because you aren't allowed to refer to the int object to access its value.

>
> > But why would referring to members of basic data types like 'int' be
> > undefined?
>
>
> If the data member is a member of a virtual base class, the vtable
> (speaking concretely) and the offsets it contains necessary to compute the
> address of that member may no longer be valid.

True, but that's also not the situation encountered in my example.

This is a justification for the general rule. The Standard has cases where a rule is more general than absolutely necessary for the sake of simplicity.

> There is an issue that [class.cdtor] is actually more restrictive here than
> [basic.life], meaning that operations that are allowed on an object fully
> outside its lifetime (principally, referring to a non-virtual base class)
> can no longer be performed once it is under construction or destruction.

But that, too, is not the situation in my Int class: there's no base class
either. It's just the plain Int class having a single int data member. So I'm
still struggling with the question why referring to its d_value data member
in the constructor's function-try-block implies undefined behavior

Your d_value might be a member via a virtual base class of Int. It isn't, but it might be.

> I'm not sure if we've got around to opening a CWG issue there.

Well, maybe I posted my question to the wrong list, but since
https://isocpp.org/about/contact specifies that questions about the standard
should be posted to this list, and since my question is about an item in the
C++ standard and not so much about C++ itself I posted the question here. I
tried several compilers with my example, and so far all resulting programs
show the line 'value = 5'.

Well, that doesn't matter that much; there's lots of UB that isn't detected by any compiler. Although it does weigh towards suggesting that it might be worth considering relaxing that UB.

But please advise if I should address the question
to 'StackOverflow C++'

No, you're in the right place. You might get an answer on SO, but they do have a tendency to see the Standard as not to be questioned. Here is a bit more relaxed.
--
Std-Discussion mailing list
Std-Discussion@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion


--
Brian Bi