2015-12-21 2 views
2

Я читал, что std::vector всегда инициализирует свои объекты своими default values, скажем, для int, это 0. То же самое должно быть применимо даже для classes, где вызывается default constructor. Однако результаты, показанные в программе испытаний немного отличаются: -std :: вектор инициализации члена класса

#include <iostream> 
#include <vector> 
using namespace std; 

class A 
{ 
    public: 
     int i; 
     A(){}; 
}; 

class B 
{ 
    public: 
     int i; 
     B() = default; 
}; 

template <typename T> 
void seev (const vector<T> &v) 
{ 
    for (auto &x:v) 
    { 
     cout << x.i << ' '; 
    } 
    cout << '\n'; 
} 

int main() 
{ 
    vector<int> vi(5); // just to show that std::vector always default initializes values & hence int will be 0 here 
    vector<A> va(5); 
    vector<B> vb(5); 

    for (auto x: vi) 
    cout << x << ' '; 
    cout << '\n'; 

    seev (va); 
    seev (vb); 
    return 0; 
} 

Выход: -

0 0 0 0 0 
8854016 0 8847696 0 8854016 
0 0 0 0 0 

Мой вопрос почему значение члена i неопределенными для A & не B ? Какая разница сделал constructor подписи: -

A() {} 

&

B() = default; 

сделать?

+0

Конструктор 'default' не означает конструктор _empty_. – YSC

ответ

3

При создании вектора определенного размера вектор не задает значения по умолчанию, он использует что-то под названием value initialization, что является чем-то совершенно другим.

Для примитивных типов, например, int, это означает, что значение будет инициализировано нулем (т. Е. Ноль). Но для объектов с конструкторами будет использоваться конструктор по умолчанию (если он есть).

В случае Вашего A класса, конструктор по умолчанию не инициализирует переменную i члена, так что это будет неинициализированным и иметь неопределенную значения, при печати, что значение вы неопределенного поведения.

Что касается класса B, это POD type, что означает, что инициализация значения всего объекта будет также инициализировать значение всеми членами. B - тип POD, потому что он имеет trivial default constructor (которого нет A).

4
A() {}; 

Вы не инициализируется A::i в A(), поэтому его значение не определено после инициализации значения. Такое поведение отличается от того, что вы получили бы с предоставленным компилятором конструктором по умолчанию.

A() = default; 

Определение, как default с другой стороны, имеет эффект обеспечивая конструктор с той же семантикой компилятора синтезировал конструктор по умолчанию. То есть A::i получит инициализацию значения (и, следовательно, инициализацию нуля), когда объект A является инициализированным значением с такими выражениями, как A() или A{}.


Примечание: это может быть исправлено либо сбросив определение конструктора по умолчанию, определить его как default, или явно инициализировать i.

struct A 
{ 
    // Compiler provided A() will initialize i 
    // when A is value initialized 
     int i; 
}; 

или, что то же самое в терминах инициализации семантики,

struct A 
{ 
     int i; 
     A() = default; // useful if other constructors defined 
}; 
+0

Я знаю, как исправить проблему @juanchopanza. Я просто хочу знать, в чем разница между 'A() {}' & 'B() = default' и почему не пуст по умолчанию инициализировать' i'. – CppNITR

+0

@CppNITR ОК, я переформулировал и изменил акцент. TL; DR вы возвращаете поведение предоставленного компилятором конструктора по умолчанию. – juanchopanza

0

«пустой» конструктор не будет ничего инициализировать, поэтому тот факт, что va содержит нуль только везение/совпадение. Конструктор default тоже ничего не сделает, поэтому они будут производить одно и то же. То, что вы видите, - это неопределенное поведение (или, возможно, неуказанное поведение - поскольку мы не должны ожидать, что мировая война три вырвется из-за неинициализированной переменной).

4

Существует разница между инициализацией по умолчанию и Инициализация значения. Разница показана на B, но не для A:

  • Когда класс имеет конструктор не- = default Е.Д., этот конструктор вызывается, когда либо по умолчанию или инициализации значения используются. Его обязанность - инициализировать всех членов надлежащим образом.

  • Когда класс либо не имеет конструктора или конструктор по умолчанию в = default Е.Д. инициализация членов зависит от того, как строятся объект: при инициализации объекта без инициализации скобки по умолчанию делается, который оставляет подобъекты без конструкторы по умолчанию UNINITIALIZED. При инициализации объекта со значением в скобках выполняется инициализация, значение которого инициализирует все подобъекты. Инициализация значений встроенных типов означает, что они получают подходящее нулевое значение, а инициализация по умолчанию встроенных типов означает, что они оставлены неинициализированными.

Поскольку A имеет явно написанный конструктор по умолчанию, его конструктор должен инициализировать все элементы, которые не имеют класса типа с конструктором по умолчанию. B имеет неявно написанный конструктор по умолчанию, а инициализация по умолчанию или инициализация значений выполняются по мере необходимости для подобъектов.

Объекты в std::vector<T> построены с использованием T() (если никакие другие аргументы не предусматривает, как в случае, например, для push_back() или emplace_back()). Для членов A, что означает, что они оставлены неинициализированными, для B членов, что означает, что они ноль инициализированы.

-1

Проблема заключается в том, что std::vector должен называть default constructor & не устанавливать значения по умолчанию. Конструктор по умолчанию int устанавливает его значение 0, поэтому вы получаете std::vector<int> со всеми значениями, инициализированными 0. Однако вы по умолчанию конструктор A пуст &, следовательно, он не инициализирует i с любым значением. Если определить конструктор, как: -

A() { i = 0; } 

Тогда ваш вектор определенно инициализировать i из объектов A с 0.Что по умолчанию делает это: -

#include <iostream> 
#include <vector> 
using namespace std; 

class A 
{ 
    public: 
     A() 
     { 
      cout << "Default constructed A\n"; 
     } 
     A (A &obj) 
     { 
      cout << "Copy constructed A\n"; 
     } 
}; 

class X 
{ 
    int x; 
    double d; 
    bool b; 
    A obj; 
    public: 
     X() = default; 
     void show() 
     { 
      cout << fixed << x << ' ' << d << ' ' << b << '\n'; 
     } 
}; 

int main() 
{ 
    cout << boolalpha; 
    vector<X> v(1); 
    v[0].show(); 
    return 0; 
} 

/* Output :- 
Default constructed A 
0 0.000000 false 
*/ 

Что B() = default; примерно означает, насколько я получаю от этого тестового кода, который является заменой для: -

B() 
{ 
    i = 0; 
    d = 0.00; 
    b = false; 
    // obj is default initialized 
} 

т.е. инициализации data members с их default values (для примитивов) или default constructors (для классов). Но это только для runtime initialization, что означает, что для локально созданных объектов определение такое же, как и B() = {}.

Так что дело в том, что класс A имел определяемый пользователем constructor (с пустым телом) & поэтому не инициализировался, потому что именно так программист определил его. С другой стороны, класс B имел конструктор, который остался в компиляторе для неявного вызова. Следовательно, для локальных объектов он не выполнял никакой конкретной инициализации, но для динамических объектов (например, std::vector) он сделал value type initialization.

+1

'int' не имеет конструктора по умолчанию, а' B() = default; 'не делает того, что вы говорите. –

+0

@BenjaminLindley я загляну в него снова, thnx для рекомендации –

+1

@BenjaminLindley Я считаю, что моя интерпретация правильная, посмотрите на инициализацию 'A obj' в классе' X'. 'default' действительно вызывает конструктор по умолчанию и да, в случае примитивов он инициализирует по умолчанию –

Смежные вопросы