Как заставить компилятор устанавливать ненулевое значение для неинициализированных переменных?

Я играю с Инициализация значения C ++.
Поэтому я печатаю неинициализированные значения, чтобы выделить (не) инициализацию в зависимости от стандартной версии C ++.
Но неинициализированные значения часто передают нулевое значение 🙁

Как выделить, если переменная не была инициализирована?
(т.е. как сказать компилятору использовать конкретное значение для неинициализированных переменных?)

Может быть, это можно сделать с помощью магия предоставленный пользователем распределитель …


РЕДАКТИРОВАТЬ: Мои нижеприведенные фрагменты не для производства. Я просто хотел проверить реализацию (компилятором) Стандарта C ++ о механизмах неинициализации / инициализации значения / инициализации нуля / инициализации по умолчанию. Я не хочу, чтобы компилятор предупреждал о неинициализированных переменных. Я не хочу использовать MemoryCheckers. Я просто хочу подчеркнуть, что компилятор инициализирует нулями некоторые переменные, инициализирует по умолчанию некоторые другие переменные и не инициализирует все остальные переменные. И это поведение инициализации также зависит от версии C ++ Standard. Если вы считаете, что лучше всего использовать предупреждения компиляторов или MemoryCheckers, предоставьте ответ, используя приведенные ниже фрагменты.


Пожалуйста, не читайте ниже подробные попытки, если вы уже поняли мой вопрос.


Вы можете построить / запустить мой первый фрагмент на Coliru

#include <iostream>

struct A  {
A() {} // user-defined default ctor does not initialize i
int i;
};

struct B {
A a;
};

int main()
{
std::cout << B().a.i << '\n';
// Results: C++03 -> uninitialized
//          C++11 -> zero-initialized

std::cout << B{}.a.i << '\n';
// Results: C++03 -> Do not compile - B{} is correct since C++11
//          C++11 -> uninitialized because
//          DR1301 defines B{} as an aggregate-initialization
}   //          => A is value-initialized using the user-defined ctor

Когда скомпилировано с использованием -std=c++03 выполнение может, вероятно, печатать нулевое значение, но я бы предпочел ненулевое значение.

0

Возможный вывод с использованием -std=c++11

0
1208617840

Еще один возможный вывод с использованием -std=c++11

0
-201855824

Но мой более продвинутый фрагмент теперь имеет нулевые значения для неинициализированного объекта B{}.a.i 🙁

#include <iostream>

struct A {
A() {} // user-defined ctor does not initialize i
int i;
};

struct B  {
A a;
};

int main()
{
std::cout <<"-----------"<< __cplusplus <<"-----------" "\n";
std::cout <<"B().a.i            = "<<         B().a.i <<'\n';
std::cout <<"B{}.a.i            = "<<         B{}.a.i <<'\n';

int d;
d = 42;
std::cout <<"(new(&d) B  )->a.i = "<< (new(&d) B  )->a.i <<'\n';
d = 42;
std::cout <<"(new(&d) B())->a.i = "<< (new(&d) B())->a.i <<'\n';
d = 42;
std::cout <<"(new(&d) B{})->a.i = "<< (new(&d) B{})->a.i <<'\n';
}

Построить / Выполнить вывод:

> g++ -std=c++03 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------199711-----------
B().a.i            = 0
(new(&d) B  )->a.i = 42
(new(&d) B())->a.i = 0

> g++ -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------201103-----------
B().a.i            = 0
B{}.a.i            = 0
(new(&d) B  )->a.i = 42
(new(&d) B())->a.i = 0
(new(&d) B{})->a.i = 0

> g++ -std=c++14 -Wall -Wextra -pedantic main.cpp && ./a.out
-----------201402-----------
B().a.i            = 0
B{}.a.i            = 0
(new(&d) B  )->a.i = 42
(new(&d) B())->a.i = 0
(new(&d) B{})->a.i = 0

3

Решение

Одним из возможных решений является использование clang++ вместо g++,

clang++ v3.7 выделил неинициализированные значения в моем конкретном случае.

Замечания: Этот ответ основан на C ++ инициализация значения что изменилось с C ++ 11. Инициализация значения происходит, когда скобки / фигурные скобки пусты: T(); T{}; new T(); new T{};

Построить / запустить под фрагментом Coliru

#include <iostream>

struct A
{
A() {} // ctor does not initialize 'i'
int i;
};

struct B // implicit ctor
{
A a;
int i;
void set() { a.i = i = 42; }
};

std::ostream& operator<< (std::ostream& os, const B& b)
{  os <<'\t'<< b.a.i <<'\t'<< b.i;  return os; }

int main()
{
std::cout <<"----------"<< __cplusplus <<"----------" "\n";

B b; // used to reset memory for 'placement new'

b.set(); std::cout <<"new(&b)B   "<< *new(&b)B   <<'\n'; // All uninitialized (in all C++ standards)

std::cout          <<"       B() "<< B()         <<'\n'; // B::A::i uninitialized in C++03, zero-initialized in C++11
b.set(); std::cout <<"new(&b)B() "<< *new(&b)B() <<'\n'; // B::i zero-initialized (in all C++ standards)

#if __cplusplus > 2011*100                                 // B{} is aggregate-initialization (DR1301)
std::cout          <<"       B{} "<< B{}         <<'\n'; // => B::A::i value-initialized
b.set(); std::cout <<"new(&b)B{} "<< *new(&b)B{} <<'\n'; // => B::i     zero-initialized
#endif
}

Построить вывод & Возможный прогон выхода

> clang++ --version
clang version 3.7.0 (tags/RELEASE_370/final 246979)
Target: x86_64-unknown-linux-gnu
Thread model: posix

> clang++ -std=c++03 -Wall -Wextra -pedantic main.cpp && ./a.out
----------199711----------
new(&b)B    42      42
B()  0       0
new(&b)B()  0       0

> clang++ -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
----------201103----------
new(&b)B    42      42
B()  0       0
new(&b)B()  0       0
B{}  4196348 0
new(&b)B{}  42      0

> clang++ -std=c++14 -Wall -Wextra -pedantic main.cpp && ./a.out
----------201402----------
new(&b)B    42      42
B()  0       0
new(&b)B()  0       0
B{}  4196348 0
new(&b)B{}  42      0

> clang++ -std=c++1z -Wall -Wextra -pedantic main.cpp && ./a.out
----------201406----------
new(&b)B    42      42
B()  0       0
new(&b)B()  0       0
B{}  4196348 0
new(&b)B{}  42      0
0

Другие решения

Других решений пока нет …