totoro
> virtual
Это не trivial, ложная тревога. Ищем дальше.
Имбирная Ведьмочка
> Ищем дальше
На этом месте хочется, повязав бантик, выкинуть книжку.
Dmitry_Milk
Отсылка к этой картинке? :)
Имбирная Ведьмочка
А, так выходит действительно default-initialization требует отсутствия скобок: https://en.cppreference.com/w/cpp/language/default_initialization
Скобки даже пустые приводят к value initialization: https://en.cppreference.com/w/cpp/language/value_initialization
где явно срабатывает пункт 2, а не 1:
1) if T is a class type with no default constructor or with a user-declared(until C++11)user-provided or deleted(since C++11) default constructor, the object is default-initialized;
2) if T is a class type with a default constructor that is not user-declared(until C++11)neither user-provided nor deleted(since C++11) (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;
Но почему я не всосал сразу, надо подумать.
P.S.
Получается ситуация "no default constructor" отличается и от "not user-declared default constructor" и от "deleted default constructor". Х/з как...
Ну да, new(ptr) int; vs new(ptr) int(); показывает, что в плюсах на самом деле есть value-конструкторы и default-конструкторы и это разные штуки, если копать прям со всей скурпулёзностью. В случае user-defined они полностью совпадают, но когда пользовательские конструкторы отсутствуют, то появляется разница.
=A=L=X=
"Инициализация" и "конструктор" — это разные вещи, не путайте.
Не всегда круглые (и фигурные) скобки ассоциированы с конструированием объекта:
https://en.cppreference.com/w/cpp/language/direct_initialization
https://en.cppreference.com/w/cpp/language/aggregate_initialization
https://godbolt.org/z/6rPdGfdvW
Один конструктор, две инициализации:
#include <memory> #include <type_traits> struct Vector { float x = 10, y, z; }; void foo1(Vector* v) { new( v) Vector; // v.x = 10; v.y v.z undefined } void foo2( Vector* v) { new( v) Vector( ); // v.x = 10; v.y = v.z = 0; } bool tt = std::is_trivially_constructible_v<Vector>; // = false
LLVM IR прямо расписывает всё как оно есть, https://godbolt.org/z/zKb7E7h8e:
#include <memory> struct Vector { float x = 10, y, z; }; // define linkonce_odr dso_local void // @Vector::Vector()( // ptr noundef nonnull align 4 dereferenceable(12) %this // ) // unnamed_addr #2 comdat align 2 // { // entry: // %this.addr = alloca ptr, align 8 // store ptr %this, ptr %this.addr, align 8 // %this1 = load ptr, ptr %this.addr, align 8 // %x = getelementptr inbounds %struct.Vector, ptr %this1, i32 0, i32 0 // store float 1.000000e+01, ptr %x, align 4 // ret void // } // Vector::Vector() { // this->x = 10.0f; // } void foo1(Vector* v) { new( v) Vector; } // define dso_local void @foo1(Vector*)(ptr noundef %v) { // entry: // %v.addr = alloca ptr, align 8 // store ptr %v, ptr %v.addr, align 8 // %0 = load ptr, ptr %v.addr, align 8 // call void @Vector::Vector()(ptr noundef nonnull align 4 dereferenceable(12) %0) // ret void // } // void foo1(void* v) { // ((Vector*)v)->Vector(); // } void foo2( Vector* v) { new( v) Vector( ); } // define dso_local void @foo2(Vector*)(ptr noundef %v) { // entry: // %v.addr = alloca ptr, align 8 // store ptr %v, ptr %v.addr, align 8 // %0 = load ptr, ptr %v.addr, align 8 // call void @llvm.memset.p0.i64(ptr align 4 %0, i8 0, i64 12, i1 false) // call void @Vector::Vector()(ptr noundef nonnull align 4 dereferenceable(12) %0) // ret void // } // void foo2(void* v) { // memset(v, 0, sizeof(Vector)); // ((Vector*)v)->Vector(); // }
Тема в архиве.