Which part of the C++ standard forbids destroying an object twice?

Which parts of a modern C++ standard (C++20 or C++23 are fine) say that it’s not okay to destroy an object twice using placement new and an explicit destructor call?

alignas(T) std::byte storage[sizeof(T)];
T* const p = new (storage) T(...);
p->~T();
p->~T();

Are there any conditions this is allowed, e.g. if T has a trivial destructor?


I found this previous answer to a semi-related question that gives a relatively clear answer the the trivial destructor part of the question, but it uses C++17 and to my surprise the wording in C++20 seems to have changed to also forbid this for trivial destructors. This seems like it should be fine for trivial destructors, so I suspect I’m missing something.

3

[basic.life]/6.2

… after the lifetime of an object has ended … The program has undefined behavior if:

— the pointer is used to … call a non-static member function of the object

Now are destructors non-static member functions? Yes, [class.mem.special]/1.

…Or, if this is a pseudo-destructor call (i.e. if T is non-class), then it’s UB for a different reason. [expr.call]/4 says it ends the lifetime of an object, and if there’s no object (because its lifetime has already ended), the precondition is false so the behavior is undefined.

Are there any conditions this is allowed, e.g. if T has a trivial destructor?

Doesn’t seem to be the case.

1

I think this is how it breaks down for C++20.

The first (pseudo)-destructor call ends the lifetime of the object.

[basic.life]/1 says that the lifetime of an object ends when its destructor is called:

The lifetime of an object o of type T ends when:

  • if T is a non-class type, the object is destroyed, or
  • if T is a class type, the destructor call starts, or
  • […]

There are two cases:

  • For non-class T, I think “object is destroyed” is defined in [expr.call]/5:

    If the postfix-expression names a pseudo-destructor (in which case the postfix-expression is a possibly-parenthesized class member access), the function call destroys the object of scalar type denoted by the object expression of the class member access.

  • For class types T it’s straightforward that we’re calling the destruct.

[basic.life]/5 is perhaps even clearer that ~T ends the lifetime of the object in both cases though:

A program may end the lifetime of any object by […] explicitly calling a destructor or pseudo-destructor for the object.

It’s UB to call a destructor on an object whose lifetime has ended

[basic.life]/6 says that it’s not okay to call a non-static member function of an object whose lifetime has ended:

[A]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 may be used but only in limited ways. […] 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 to access a non-static data member or call a non-static member function of the object, or
  • […]

Calling the destructor a second time is therefore undefined behavior because it involves calling a non-static member function of the object (the destructor).

…At least if the object has class type. It’s not clear this precisely applies to non-class objects, particularly given the distinction about destructors versus pseudo-destructors mentioned above. Is ~int really a member function of int? But HolyBlackCat points out that maybe this is covered instead by [expr.call]/5 again: it says that a pseudo-destructor call ends the lifetime of an object, but if the object’s lifetime has already ended are the preconditions really met?

This is more restrictive than in C++17.

In C++17, [basic.life]/1 specifically carved out an exception to the first point, saying only that the lifetime of a class type with a non-trivial destructor ended when the destructor call started. Similarly with [basic.life]/5. So it was okay to double destroy trivially destructible types in C++17.

This seems to have been an intentional change: CWG issue 2256 says that this was changed to make the lifetime model more consistent. It’s short on details about the large context of why this is desirable, and I’m not sure I get it because you can still do weird lifetime things with trivial types like reuse their storage without destroying them as far as I can tell.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật