So i have this class called point, just to log to the console everytime an object gets constructed and destroyed. And i did the following:
#include <iostream>
struct point{
point() {
std::cout << "ctor\n";
}
~point() {
std::cout << "dtor\n";
}
};
int main(){
int x = 3;
point* ptr = new point[x]{point()};
delete[] ptr;
}
ctor
dtor
dtor
dtor
This ended up calling the constructor just once, and the destructor 3 times, why? I know that this is bad, probably ub, but i would like to understand why. This other allocations give me the "expected" output:
int x = 3;
constexpr int y = 3;
point* ptr1 = new point[3];
point* ptr2 = new point[x];
point* ptr3 = new point[y]{point()};
ctor
ctor
ctor
dtor
dtor
dtor
Im using visual studio 19 latest version.
Allocating array objects in C++ In C++, you allocate arrays using array new-expressions of the form new T [n] . Such expressions return a T * pointing to the first element in the allocated array.
dynamically allocated arrays To dynamically allocate space, use calls to malloc passing in the total number of bytes to allocate (always use the sizeof to get the size of a specific type). A single call to malloc allocates a contiguous chunk of heap space of the passed size.
Statically declared arrays are allocated memory at compile time and their size is fixed, i.e., cannot be changed later. They can be initialized in a manner similar to Java. For example two int arrays are declared, one initialized, one not. Static multi-dimensional arrays are declared with multiple dimensions.
As expected, an n array must be declared prior its use. A typical declaration for an array in C++ is: type name [elements]; where type is a valid type (such as int, float ...), name is a valid identifier and the elements field (which is always enclosed in square brackets [] ), specifies the size of the array.
This is a compiler bug.
By using operator new without a constant defined type size MSVC compiler will call the class object constructor and destructor as many times as explicitly specified at initializer list and/or array size.
#include <iostream>
struct point {
point() {
std::cout << "ctor\n";
}
~point() {
std::cout << "dtor\n";
}
};
int main() {
int x = 3;
point* ptr = new point[x]{point()};
delete[] ptr;
}
As stated will call as explicitly specified point
ctor once.
This can be asserted by: point* ptr = new point[x]{point(), point()};
ctor ctor dtor dtor dtor
.ctor ctor ctor dtor dtor dtor
(which should be guaranteed)And even a throwable array out of bound exception UB: point* ptr = new point[x]{point(), point(), point(), point(), point() };
follows the behavior.
ctor ctor ctor ctor ctor dtor dtor dtor
.terminate called after throwing an instance of 'std::bad_array_new_length'
Too many initializers is correctly detected if the defined size is constant. i.e const int x = 3
or constexpr int x = 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With