Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[basic.types.general] Clarify undefined behavior with overwriting object representations of non-trivially-copyable objects #652

Open
frederick-vs-ja opened this issue Dec 11, 2024 · 2 comments

Comments

@frederick-vs-ja
Copy link

frederick-vs-ja commented Dec 11, 2024

Full name of submitter (unless configured in github; will be published with the issue): Jiang An

Reference (section label): [basic.types.general]

Link to reflector thread (if any):

Issue description:

It's widely believed that [basic.types.general] p2 and p3 imply undefined behavior with copying or overwriting object representations of non-trivially-copyable objects. However, we're not explicity specifying such UB.

The situation is unclear when a non-trivially-copyable class objects has no padding byte and all of its subobjects are of trivially coypable types. It probably makes no sense to say the behavior is well-defined when the same underlying bytes are considered belonging to subobjects, while being undefined when considering underlying bytes to belong to the enclosing object.

Outdated concerns

It's also unclear whether operations mentioned in [basic.types.general] p2 and p3 copy object representations. Curiously, the term object representation is defined a bit later in p4.

This part is currently addressed by P2434R3.

Suggested resolution:

@jensmaurer
Copy link
Member

memcpy is reusing storage for an object, thus the lifetime of the existing object ends per [basic.life] p2.

Since reading the object representation is a thing (see https://wg21.link/p1839r6), it seems the actual memcpy is not undefined behavior, but any subsequent read of the target object is, because the object is out-of-lifetime.

What additional clarity are you seeking?

@frederick-vs-ja
Copy link
Author

memcpy is reusing storage for an object, thus the lifetime of the existing object ends per [basic.life] p2.

This is one possible choice when the behavior is well-defined. However, given implicit object creation possibly creates zero new object, it seems possible that memcpy just replaces object representations and keeps existing objects living. On the other hand, for classes with virtual functions or virtual base classes, perhaps there should be some guarantee that the lifetime is ended (or there's immediately UB), but implicit object creation doesn't seem suitable.

Moreover, there can be weird trivially copyable classes that are not implicit-lifetime. E.g. such a class can have trivial assignment operators and destructor, but its default, copy, and move constructors are either deleted or not declared. Current wording seemingly states that memcpy over such class objects may have guaranteed well-defined behavior, while storage reusing and implicit object creation don't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants