Функция шаблона, которая возвращает значение по умолчанию

У меня есть функция, которая возвращает построенное по умолчанию значение типа шаблона:

template<typename T>
T do_stuff()
{
    return T();
}

Я использую его следующим образом:

int main(int argc, char** argv)
{
    std::string str("hello");
    int a = 10;
    int *p = &a;

    str = do_stuff<std::string>();
    a = do_stuff<int>();
    p = do_stuff<int*>();

    return 0;
}

После его использования у меня есть: str - пустая строка, a eqauls 0 и p - пустой указатель. Я могу понять, почему переменная std::string становится пустой строкой (у нее есть конструктор по умолчанию, который создает пустую строку). Но почему переменная int становится 0, а указатель становится нулевым указателем. Это поведение шаблона по умолчанию?

Я использую gcc 4.6.6 под Linux Centos.

Ответ 1

От эта ссылка на инициализацию значения:

  • Если T - тип класса с хотя бы одним предоставленным пользователем конструктором любого типа, вызывается конструктор по умолчанию.

  • Если T - тип неединичного класса без каких-либо конструкторов, предоставляемых пользователем, тогда объект инициализируется нулем, а затем вызывается неявно объявленный конструктор по умолчанию (если только он не является тривиальным)

  • Если T - тип массива, каждый элемент массива инициализируется значением

  • В противном случае объект инициализируется нулем.

Что происходит, так это то, что последний пункт в приведенном выше списке.

Ответ 2

Ключ находится в

//------vv
return T();

Например, вы можете протестировать следующее, что эквивалентно:

int x =  int();
std::cout << x;

x всегда будет 0 в этом случае. То же самое применяется для указателя - он инициализируется нулем, "делая" его NULL.

Это инициализация значения, вызванная скобкой.

Ответ 3

Поскольку T() - инициализация значения, которая для int и типов указателей (и других базовых типов) имеет нулевую инициализацию.

Точно так же, как значение инициализировать int, вы бы сделали:

int x{};
int x = int();

//not initialized:
int x;   //if not at namespace scope
int x(); //method declaration

Ответ 4

Это определено в стандарте С++ 11, раздел 8.5:

Для инициализации объекта типа типа T означает:

- если T - тип класса (раздел 9) с объявленным пользователем конструктором (12.1), тогда вызывается конструктор по умолчанию для T (и инициализация плохо сформирована, если T не имеет доступного конструктора по умолчанию);

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

- если T - тип массива, то каждый элемент инициализируется значением;

- , в противном случае объект инициализируется нулем

и

Для инициализации объекта типа T по умолчанию:

- если T - тип класса не-POD (раздел 9), вызывается конструктор по умолчанию для T (и инициализация плохо сформированный, если T не имеет доступного конструктора по умолчанию);

- если T - тип массива, каждый элемент инициализируется по умолчанию;

- , в противном случае объект инициализируется нулем.

и

Для нулевой инициализации объекта типа T означает:

- если T является скалярным типом (3.9), объект устанавливается в значение 0 (ноль), преобразованное в T;

- если T - тип неединичного класса, каждый нестатический член данных и каждый подобъект базового класса инициализируются нулем;

- если T - тип объединения, объекты, сначала названные элементом данных 89) инициализируются нулем;

- если T - тип массива, каждый элемент инициализируется нулем; - если T является ссылочным типом, инициализация не выполняется.

Ответ 5

Это правильное поведение для соответствующих типов, везде.

Примитивные типы инициализируются по-разному в зависимости от того, явно ли вы запрашиваете значение по умолчанию (инициализация значения) или не упоминаете инициализацию (инициализация по умолчанию).

Если вы создаете примитивный тип без упоминания инициализации (это называется инициализацией по умолчанию), значение является случайным:

int x;
struct Y {
    int x;
} x;
int *x = new int;

- все инициализации по умолчанию и будут содержать случайное значение.

Но если вы упомянете инициализатор, он становится инициализацией значения, и значение инициализируется соответствующим "нулем" (0 для чисел, 0/nullptr для указателей):

int x = 0;
int x = int();
struct Y {
    int x;
    Y() : x() {} // the x() is important
} y;
struct Z {
    int x;
} z = {};
int *x = new int();

- все инициализации значений, а С++ 11 добавляет следующие формы

int x{};
struct Y {
    int x;
    Y() : x{} {}
} y;
struct Z {
    int x;
} z{};
int *x = new int{};

Остерегайтесь

int x(); // function, NOT A VARIABLE

объявляет функцию без аргументов и возвращает int. Это называется "самым неприятным анализом".

Ответ 6

T() - инициализация значения.

Использование:

int x{};
int x = int();

Ответ 7

Просто потому, что это происходит в вашей среде, это не значит, что это ожидаемое поведение и что это произойдет в разных средах.

На него могут повлиять многие вещи: версия ОС, версия компилятора, флаги компилятора (уровень оптимизации, информация об отладке и т.д.).