Re[2]: Вопрос по value-initialization
От: Лазар Бешкенадзе СССР  
Дата: 17.05.17 20:06
Оценка: +1
Здравствуйте, rumit7, Вы писали:

R>
R>struct A
R>{
R>    int i;
R>    A() { } // user-provided default ctor, does not initialize i
R>};
 
R>struct B { A a; }; // implicitly-defined default ctor
 
R>std::cout << B().a.i << '\n'; // value-initializes a B temporary
R>                              // leaves b.a.i uninitialized in C++03
R>                              // sets b.a.i to zero in C++11
R>


Вообще говоря это был мой способ обходить это #$@# обнуление. Выходит после 11 меня все равно обнулят если не озаботиться во всех производных?
Это — отстой. Очевидно что если мне надо обнулить я могу это сделать явно. Если я явно не инициализирую значит мне это не нужно. C++ скатился в говно.
Re[3]: Вопрос по value-initialization
От: jazzer Россия Skype: enerjazzer
Дата: 20.05.17 05:50
Оценка:
Здравствуйте, Лазар Бешкенадзе, Вы писали:

R>>
R>>std::cout << B().a.i << '\n'; // value-initializes a B temporary
R>>                              // sets b.a.i to zero in C++11
R>>


ЛБ>Вообще говоря это был мой способ обходить это #$@# обнуление. Выходит после 11 меня все равно обнулят если не озаботиться во всех производных?

ЛБ>Это — отстой. Очевидно что если мне надо обнулить я могу это сделать явно. Если я явно не инициализирую значит мне это не нужно. C++ скатился в говно.

Вообще-то, B() — это и есть явная инициализация.
Если хотите без инициализации, то пишите так:
B b;
std::cout << b.a.i << '\n';
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Вопрос по value-initialization
От: Лазар Бешкенадзе СССР  
Дата: 20.05.17 07:39
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Вообще-то, B() — это и есть явная инициализация.


Вообще-то с самого начала это было просто вызовом default конструктора. Но уже тогда просматривался будущий идиотизм потому что вместо того чтобы int() считать неинициализированным объектом типа int его объявили просто нулем — 0.

Вообще-то value initialization была введена только в 2003 но тогда хоть оставили лазейку чтобы от этой медвежьей услуги отказаться.

Вообще-то теперь это уже пипец.

J>Если хотите без инициализации, то пишите так:

J>
J>B b;
J>std::cout << b.a.i << '\n';
J>


Вообще-то меня уже зае...о переписывать с появлением нового стандарта.

Вообще-то твой совет не поможет если нужен временный объект.

Вообще-то разумно это считать вызовом default конструктора, если B(5) считается вызовом конструктора B(int).

Вообще-то я не удивлюсь если сейчас все обнуляют и в этом случае.

Вообще-то в твоем примере объект будет висеть до конца блока что не совсем то же самое и чтобы сделать похоже на то что в оригинале надо сделать так:

{
   B b;
   std::cout << b.a.i << '\n';
}


Согласись это весело.
Отредактировано 20.05.2017 7:51 Лазар Бешкенадзе . Предыдущая версия .
Re[5]: Вопрос по value-initialization
От: jazzer Россия Skype: enerjazzer
Дата: 20.05.17 08:43
Оценка:
Здравствуйте, Лазар Бешкенадзе, Вы писали:

ЛБ>Вообще-то твой совет не поможет если нужен временный объект.


Еще можно B{}.a.i — в этом случае это инициализация агрегата, которая ничего не обнуляет.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: Вопрос по value-initialization
От: N. I.  
Дата: 20.05.17 12:02
Оценка: 3 (2)
Лазар Бешкенадзе:

J>>Вообще-то, B() — это и есть явная инициализация.


ЛБ>Вообще-то с самого начала это было просто вызовом default конструктора.


И что дальше с этим B() можно было делать (не меняя ничего в классе B)? Попытка передать его куда-нибудь по ссылке могла бы привести к undefined behavior, т.к. реализация была вправе делать копию объекта при инициализации ссылки на const rvalue-выражением, а копирование неинициализированного скалярного объекта неявно сгенерированным копирующим конструктором A влечёт неопределённое поведение. Попытка снять const с копии и присвоить i какое-нибудь значение тоже бы повлекла неопределённое поведение.

Чтоб хоть как-то поюзать такое выражение, пришлось бы что-то поменять в A или B — например, добавить в B

B &as_lvalue() { return *this; }

чтоб потом гарантированно получить прямой доступ к временному объекту через B().as_lvalue().

ЛБ>Но уже тогда просматривался будущий идиотизм потому что вместо того чтобы int() считать неинициализированным объектом типа int его объявили просто нулем — 0.


По-моему, лучше бы инициализированное состояние было по умолчанию и неинициализированное — по явному требованию, а не наоборот. Наличие или отсутствие избыточной инициализации реально может повлиять на производительность только в каких-то специфичных случаях, а вот баги из-за пропущенной инициализации могут вылезти где угодно.

ЛБ>Вообще-то value initialization была введена только в 2003 но тогда хоть оставили лазейку чтобы от этой медвежьей услуги отказаться.


Стоит помнить, что инициализация нулями — это не более, чем часть формального описания observable behavior; реального же контроля над ходом вычислений в существующих средах исполнения программ стандартизированный C++ никогда не давал. Правила C++ составлялись и продолжают составляться исходя из концепции, подразумевающей, что довольно большую часть решений о том, как именно что-то будет вычисляться, берёт на себя оптимизатор, а не автор кода на C++. В данном случае если оптимизатор способен определить, что инициализировать объект нулями избыточно (в том плане, что такая инициализация не влияет на итоговый результат), то он может лишнюю инициализацию убрать. Видимо, на это и был расчёт, когда вводилось столь навязчивое заполнение нуликами (теперь ими даже padding bits забиваются).

ЛБ>Вообще-то теперь это уже пипец.


Меня больше впечатлило слияние new-выражений в C++14:

void mergeable(int x) {
    // These heap allocations are safe for merging:
    std::unique_ptr<char[]> a{new (std::nothrow) char[8]};
    std::unique_ptr<char[]> b{new (std::nothrow) char[8]};
    std::unique_ptr<char[]> c{new (std::nothrow) char[x]};
    g(a.get(), b.get(), c.get());
}

Тут оптимизатор может объединить три new-выражения в одно, сделав из этого кода что-то наподобие

void mergeable(int x) {
    std::unique_ptr<char[]> a{new (std::nothrow) char[8 + 8 + x]};
    char *__b = a.get() ? a.get() + 8 : nullptr;
    char *__c = __b ? __b + 8 : nullptr;
    g(a.get(), __b, __c);
}

Получается, что из-за невозможности выделить большой кусок памяти, образованный объединением трёх частей, соответствующих отдельным new-выражениям, мы можем получить фэйл для каждого из этих new-выражений, даже если какое-то их непустое подмножество могло бы удачно выделить память частями указанных в программе размеров. Довольно выразительный пример того, как контроль за исполнением программы ускользает из рук программиста.
Отредактировано 20.05.2017 12:06 N. I. . Предыдущая версия .
Re[6]: Вопрос по value-initialization
От: N. I.  
Дата: 20.05.17 12:02
Оценка:
jazzer:

J>Еще можно B{}.a.i — в этом случае это инициализация агрегата, которая ничего не обнуляет.


Ага, зачётная пакость со стороны авторов правил. В C++11 i гарантированно обнулялось, а в C++14 и в C++17 — уже нет.
Re[6]: Вопрос по value-initialization
От: Лазар Бешкенадзе СССР  
Дата: 20.05.17 13:07
Оценка: -1 :)
Здравствуйте, N. I., Вы писали:

ЛБ>>Вообще-то с самого начала это было просто вызовом default конструктора.


NI>И что дальше с этим B() можно было делать (не меняя ничего в классе B)? Попытка передать его куда-нибудь по ссылке могла бы привести к undefined behavior, т.к. реализация была вправе делать копию объекта при инициализации ссылки на const rvalue-выражением, а копирование неинициализированного скалярного объекта неявно сгенерированным копирующим конструктором A влечёт неопределённое поведение. Попытка снять const с копии и присвоить i какое-нибудь значение тоже бы повлекла неопределённое поведение.


Я не понял о чем ты говоришь. Я говорил о том что было до 2003. Я всегда писал B b = new B(). Просто потому что это единообразно с остальными конструкторами. Никаких undefined с копированием неинициализированных объектов не было. Если ты имеешь ввиду привязку временных объектов к const ссылкам так это было самая большая куча дерьма в первом стандарте. Но я, слава богу, пользовался только VC а в Microsoft положили на это правило х.., за что я им безмерно благодарен.

ЛБ>>Вообще-то value initialization была введена только в 2003 но тогда хоть оставили лазейку чтобы от этой медвежьей услуги отказаться.


NI>Стоит помнить, что инициализация нулями — это не более, чем часть формального описания observable behavior


Какое observable behavior? Не думаю что хоть один уважающий себя производитель компилятора стал бы обнулять что-то до вызова конструктора.

NI>Меня больше впечатлило слияние new-выражений в C++14:


Я считаю что единственное полезное что появилось в C++11 это variadic templates. Все остальное, включая auto типы, ссылки на rvalue, move конструкторы, лямбды и инициализация мне нах не нужны. А C++14 и дальше меня просто не интересует.
Re[7]: Вопрос по value-initialization
От: N. I.  
Дата: 20.05.17 16:21
Оценка:
Лазар Бешкенадзе:

NI>>И что дальше с этим B() можно было делать (не меняя ничего в классе B)? Попытка передать его куда-нибудь по ссылке могла бы привести к undefined behavior, т.к. реализация была вправе делать копию объекта при инициализации ссылки на const rvalue-выражением, а копирование неинициализированного скалярного объекта неявно сгенерированным копирующим конструктором A влечёт неопределённое поведение. Попытка снять const с копии и присвоить i какое-нибудь значение тоже бы повлекла неопределённое поведение.


ЛБ>Я не понял о чем ты говоришь. Я говорил о том что было до 2003.


Я про C++98 говорил.

ЛБ>Я всегда писал B b = new B(). Просто потому что это единообразно с остальными конструкторами.


Единообразие — это не про C++. Стандарт C++ всегда описывал кучу специальных случаев то на одно, то на другое. Например, new T() ведёт себя по-разному в зависимости от того, является T типом-массивом или нет. Если надо, чтоб new-выражение делало default-initialization, не следует туда сувать эти круглые скобочки.

ЛБ>Если ты имеешь ввиду привязку временных объектов к const ссылкам


Именно её.

NI>>Стоит помнить, что инициализация нулями — это не более, чем часть формального описания observable behavior


ЛБ>Какое observable behavior?


Такое, какое описано в разделе [intro.execution] стандарта. Обнуление происходит на некоей воображаемой абстрактной машине, что позволяет нам предсказать результат работы программы (а точнее, её observable behavior). От реальной реализации не требуется чего-то там обнулять или даже создавать в памяти аналог объекта, который был бы создан на абстрактной машине. От реализации требуется лишь получение результата, который мог бы получиться на абстрактной машине описанным стандартом путём. Некоторые оптимизации, меняющие observable behavior, описаны явным образом. Например, правила C++14 позволяют убирать вызовы replaceable функций operator new и operator delete из new-выражений и delete-выражений, даже если эти функции переопределены пользователем и делают что-то такое, что влияет на observable behavior (например, пишут в файл). Вот такую программу

#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <new>

void *operator new(std::size_t size)
{
    if (void *p = std::malloc(size))
    {
        std::printf("allocation size: %zu\n", size);
        return p;
    }
    throw std::bad_alloc();
}

void operator delete(void *p) noexcept
{
    std::printf("deallocation\n");
    std::free(p);
}

void operator delete(void *p, [[maybe_unused]] std::size_t size) noexcept
{
    operator delete(p);
}

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

struct B { A a; }; // implicitly-defined default ctor

int main()
{
    try
    {
        B *b = new B();
        b->a.i = 10;
        std::printf("b->a.i: %d\n", b->a.i);
        delete b;
    }
    catch (std::bad_alloc &)
    {
        std::printf("out of memory");
    }
}

допустимо соптимизировать до эквивалента следующего кода

#include <cstdio>

int main()
{
    std::printf("b->a.i: %d\n", 10);
}

ЛБ>Я считаю что единственное полезное что появилось в C++11 это variadic templates. Все остальное, включая auto типы, ссылки на rvalue, move конструкторы, лямбды и инициализация мне нах не нужны. А C++14 и дальше меня просто не интересует.

Ну, не у всех такие скромные запросы.
Отредактировано 20.05.2017 16:24 N. I. . Предыдущая версия .
Re[8]: Вопрос по value-initialization
От: Лазар Бешкенадзе СССР  
Дата: 20.05.17 17:12
Оценка: -1 :)
Здравствуйте, N. I., Вы писали:

NI>Я про C++98 говорил.


ЛБ>>Я всегда писал B b = new B(). Просто потому что это единообразно с остальными конструкторами.


NI>Например, new T() ведёт себя по-разному в зависимости от того, является T типом-массивом или нет.


Мы говорили о классах. Причем тут массивы?

NI>>>Стоит помнить, что инициализация нулями — это не более, чем часть формального описания observable behavior


ЛБ>>Какое observable behavior? Не думаю что хоть один уважающий себя производитель компилятора стал бы обнулять что-то до вызова конструктора.


NI>Такое, какое описано в разделе [intro.execution] стандарта. Обнуление происходит на некоей воображаемой абстрактной машине


Было трудно но я нашел текст стандарта 1998 года. В этом разделе нет ничего про обнуление.

Ты вертишься как уж на сковородке и из-за тебя я попусту потерял время. Можешь продолжать но уже без меня.
Re[9]: Вопрос по value-initialization
От: N. I.  
Дата: 20.05.17 18:00
Оценка:
Лазар Бешкенадзе:

ЛБ>Мы говорили о классах. Причем тут массивы?


Не нравится пример с массивами — вот пример с классом:

#include <iostream>

struct C
{
    int i;
};

int main()
{
    std::cout << C().i << std::endl;
}

По правилам C++98 и C++03 выражение C() не использует никакие конструкторы.

ЛБ>Было трудно но я нашел текст стандарта 1998 года. В этом разделе нет ничего про обнуление.


Про обнуление в отдельности там ничего и не должно быть. Это общие правила, определяющие смысл остальной части стандарта. Оттуда следует, что в соптимизированной компилятором программе того избыточного обнуления, о котором ты так сильно озаботился, вполне может не быть, и более-менее современные компиляторы реально умеют делать такую оптимизацию, пусть и не во всех случаях.
Отредактировано 20.05.2017 20:47 N. I. . Предыдущая версия .
Re[7]: Вопрос по value-initialization
От: _NN_ www.nemerleweb.com
Дата: 31.07.17 18:49
Оценка:
Здравствуйте, _NN_, Вы писали:

Не прошло и года:
Thanks for your report! This issue has been fixed and will be available in the next major release of VS2017.

Осталось узнать что означает сегодня 'major release'
http://rsdn.nemerleweb.com
http://nemerleweb.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.