Home > database >  Is it really possible to separate storage allocation from object initialization?
Is it really possible to separate storage allocation from object initialization?

Time:09-16

From [basic.life/1]:

The lifetime of an object or reference is a runtime property of the object or reference. A variable is said to have vacuous initialization if it is default-initialized and, if it is of class type or a (possibly multi-dimensional) array thereof, that class type has a trivial default constructor. The lifetime of an object of type T begins when:

  • storage with the proper alignment and size for type T is obtained, and
  • its initialization (if any) is complete (including vacuous initialization) ([dcl.init]),

except that if the object is a union member or subobject thereof, its lifetime only begins if that union member is the initialized member in the union ([dcl.init.aggr], [class.base.init]), or as described in [class.union] and [class.copy.ctor], and except as described in [allocator.members].

From [dcl.init.general/1]:

If no initializer is specified for an object, the object is default-initialized.

From [basic.indet/1]:

When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced ([expr.ass]). [Note 1: Objects with static or thread storage duration are zero-initialized, see [basic.start.static]. — end note]

Consider this C program:

int main() {
    int i;
    i = 3;
    return 0;
}

Is initialization performed in the first statement int i; or second statement i = 3; of the function main according to the C standard?

I think it is the former, which performs vacuous initialization to an indeterminate value and therefore begins the lifetime of the object (the latter does not perform initialization, it performs assignment to the value 3). If that is so, is it really possible to separate storage allocation from object initialization?

CodePudding user response:

If that is so, is it really possible to separate storage allocation from object initialization?

Yes:

void *ptr = malloc(sizeof(int));

ptr points to allocated storage, but no objects live in that storage (C 20 says that some objects may be there, but nevermind that now). Objects won't exist unless we create some there:

new(ptr) int;

CodePudding user response:

You are getting confused between allocating storage for an object and initializing an object, and they are definitely not the same thing.

In your example, the object i is never initialized. As a local value, it has space reserved for its storage, but it is not initialized with any value.

The second line’s statement assigns a value of 3 to it. This again is not initialization.

Objects with global storage are required by the standard to be both allocated and initialized (to zero or whatever the default initializer does). All other objects are only initialized if the written language construct can support it.

C allocators work on this same distinction. The new operator, behind the scenes, both allocates and initializes objects, after which you may assign the object a new value. If you need to, though, you can use the underlying language constructs to manage the two things separately.

For most purposes you do not need to care about the difference between object initialization and assignment in your code. If you get to the point where it matters, you either already know how the concepts differ or need to learn really quickly.

CodePudding user response:

Is initialization performed in the first statement int i; or second statement i = 3; of the function main according to the C standard?

The first. The second statement is assignment, not initialization. The second statement marks the point "until that value is replaced ([expr.ass])" from your quotes of the standard.

If [initialization is the first statement] is so, is it really possible to separate storage allocation from object initialization?

Yes, but not in a such a simple example as yours. A common example that comes to mind is a std::vector. Reserving capacity allocates storage space, but that storage is not initialized until an object is added to the vector.

std::vector<int> v;   // Allocates and initializes the vector object.
v.reserve(1);         // Ensures space has been allocated for an int object.
/*
 At this point, the first contained element has space allocated, but has
 not yet been initialized. If you want to do nutty things between allocation
 and object initialization, this is the place to do it. Note that you are
 not allowed to access the allocated space since it belongs to the vector.
 You'd have to replicate the inner workings of a vector to do that...
*/
v.emplace_back(3);    // Initializes the first contained object.
  • Related