Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copying structs with uninitialized members

Is it valid to copy a struct some of whose members are not initialized?

I suspect it is undefined behavior, but if so, it makes leaving any uninitialized members in a struct (even if those members are never used directly) quite dangerous. So I wonder if there is something in the standard that allows it.

For instance, is this valid?

struct Data {
  int a, b;
};

int main() {
  Data data;
  data.a = 5;
  Data data2 = data;
}
like image 596
Tomek Czajka Avatar asked Feb 07 '20 11:02

Tomek Czajka


2 Answers

Yes, if the uninitialized member is not an unsigned narrow character type or std::byte, then copying a struct containing this indeterminate value with the implicitly defined copy constructor is technically undefined behavior, as it is for copying a variable with indeterminate value of the same type, because of [dcl.init]/12.

This applies here, because the implicitly generated copy constructor is, except for unions, defined to copy each member individually as if by direct-initialization, see [class.copy.ctor]/4.

This is also subject of the active CWG issue 2264.

I suppose in practice you will not have any problem with that, though.

If you want to be 100% sure, using std::memcpy always has well-defined behavior if the type is trivially copyable, even if members have indeterminate value.


These issues aside, you should always initialize your class members properly with a specified value at construction anyway, assuming you don't require the class to have a trivial default constructor. You can do so easily using the default member initializer syntax to e.g. value-initialize the members:

struct Data {
  int a{}, b{};
};

int main() {
  Data data;
  data.a = 5;
  Data data2 = data;
}
like image 53
walnut Avatar answered Oct 20 '22 17:10

walnut


In general, copying uninitialized data is undefined behavior because that data may be in a trapping state. Quoting this page:

If an object representation does not represent any value of the object type, it is known as trap representation. Accessing a trap representation in any way other than reading it through an lvalue expression of character type is undefined behavior.

Signalling NaNs are possible for floating point types, and on some platforms integers may have trap representations.

However, for trivially copyable types it is possible to use memcpy to copy the raw representation of the object. Doing so is safe since the value of the object is not interpreted, and instead the raw byte sequence of the object representation is copied.

like image 13
Andrey Semashev Avatar answered Oct 20 '22 19:10

Andrey Semashev