This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116c. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2025-03-09


3001. Inconsistent restrictions for static_cast on pointers to out-of-lifetime objects

Section: 6.7.4  [basic.life]     Status: open     Submitter: Cody Miller     Date: 2025-02-26

According to 6.7.4 [basic.life] paragraph 7, converting a pointer-to-derived to pointer-to-base for an out-of-lifetime object is allowed implicitly, but disallowed using static_cast. That seems inconsistent.

Also, the out-of-lifetime rules mishandle this example:

  int a;
  int *p = &a;
  *p = 1;
  new (p) int;

Possible resolution:

  1. Change 7.3.12 [conv.ptr] paragraph 3 as follows:

    ... Otherwise, if B is a virtual base class of D or a base class of a virtual base class of D and v does not point to an object whose type is similar (7.3.6 [conv.qual]) to D and that is within its lifetime or within its period of construction or destruction (11.9.5 [class.cdtor]), the behavior is undefined. ...
  2. Change in 6.7.4 [basic.life] paragraph 7 as follows:

    Before the lifetime of an object has started but after the storage which the object will occupy has been allocated [ Footnote: ...] or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located points to the object may be used but only in limited ways. For an object under construction or destruction, see 11.9.5 [class.cdtor]. Otherwise, such a pointer refers to allocated storage (6.7.6.5.2 [basic.stc.dynamic.allocation]), and using the pointer as if the pointer were of type void* is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if
    • the pointer is used as the operand of a delete-expression,
    • the pointer is used to access a non-static data member or call a non-static member function of the object, or
    • the pointer is implicitly converted (7.3.12 [conv.ptr], 7.6.1.9 [expr.static.cast]) to a pointer to a virtual base class or to a base class thereof, or
    • the pointer is used as the operand of a static_cast (7.6.1.9 [expr.static.cast]), except when the conversion is to pointer to cv void, or to pointer to cv void and subsequently to pointer to cv char, cv unsigned char, or cv std::byte (17.2.1 [cstddef.syn]), or
    • the pointer is used as the operand of a dynamic_cast (7.6.1.7 [expr.dynamic.cast]).