Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can we not create trivially constructible objects using malloc if the trivial default constructor performs no action?

I have difficulty in understanding the following paragraph quoted from cppreference about trivial default constructor. I have searched stackoverflow but still didn't get a clear answer. So please help.

A trivial default constructor is a constructor that performs no action. All data types compatible with the C language (POD types) are trivially default-constructible. Unlike in C, however, objects with trivial default constructors cannot be created by simply reinterpreting suitably aligned storage, such as memory allocated with std::malloc: placement-new is required to formally introduce a new object and avoid potential undefined behavior.

Specifically, if the trivial default constructor does nothing, why cannot we reinterpret the storage and pretend there is an object with the given type? Could you please provide some examples for the potential undefined behavior that this would cause?

like image 746
doraemon Avatar asked Nov 26 '19 15:11

doraemon


People also ask

Is trivially default constructible?

A trivially default constructible type is a type which can be trivially constructed without arguments or initialization values, either cv-qualified or not. This includes scalar types, trivially default constructible classes and arrays of such types.

What is default constructible C++?

A default constructible class is a class that has a default constructor (either its implicit constructor or a custom defined one). The is_default_constructible class inherits from integral_constant as being either true_type or false_type, depending on whether T is default constructible.


2 Answers

P0593R5 "Implicit creation of objects for low-level object manipulation" gives this example:

struct X { int a, b; };
X *make_x() {
  X *p = (X*)malloc(sizeof(struct X));
  p->a = 1;
  p->b = 2;
  return p;
}

and explains:

When compiled with a C++ compiler, this code has undefined behavior, because p->a attempts to write to an int subobject of an X object, and this program never created either an X object nor an int subobject.

Per [intro.object]p1 (C++17 Draft N4659),

An object is created by a definition, by a new-expression, when implicitly changing the active member of a union, or when a temporary object is created.

... and this program did none of these things.

In practice this works and the UB situation is considered more as a defect in the standard than anything else. The whole objective of the paper is to propose a way to fix that issue and similar cases without breaking other things.

like image 76
AProgrammer Avatar answered Sep 22 '22 06:09

AProgrammer


For "purity" reason.

The alternative and the actual status quo was that every region of storage would contain all objects fitting in that storage, at the same time. Some committee members are uneasy with the status quo and a lot of people feared the notion of having infinitely many objects at the same place (in a virtual, uninitialized state).

Nobody has ever been able to show a logic issue with having infinitely many objects in a region of storage.

Because they had different sections of the standard saying contradicting things, committee members just decided to take seriously one of the worst part of the standard.

Also, using string literals is strictly not allowed, if you really take seriously that one part of the standard.

like image 35
curiousguy Avatar answered Sep 22 '22 06:09

curiousguy