простой вопрос. неопределенность ?
От: кубик  
Дата: 14.06.15 11:39
Оценка: -2
Всем привет,

Имеем:
//////////////////////////////
int x;
x= 1;
for (..) {
x=2;
vector v(x);
}

//////////////////////////////
Я так понимаю что вектор может сконструируюется в начале скопа, а не по порядку после того как x==2. Так ?
Re: простой вопрос. неопределенность ?
От: Vamp Россия  
Дата: 14.06.15 12:08
Оценка:
К>//////////////////////////////
К>Я так понимаю что вектор может сконструируюется в начале скопа, а не по порядку после того как x==2. Так ?
Нет, не может в данном случае. Что вероятно с оптимизирующим компилятором — первое присваивание вообще будет забыто, и i инициализируется 2.
Да здравствует мыло душистое и веревка пушистая.
Re: простой вопрос. неопределенность ?
От: Ops Россия  
Дата: 14.06.15 13:22
Оценка: 4 (1)
Здравствуйте, кубик, Вы писали:

К>Я так понимаю что вектор может сконструируюется в начале скопа, а не по порядку после того как x==2. Так ?

Нет. Не может нарушаться видимое поведение.

Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.

А оно такое:

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Отредактировано 16.06.2015 19:25 ути-пути . Предыдущая версия .
Re: простой вопрос. неопределенность ?
От: Mr.Delphist  
Дата: 16.06.15 11:32
Оценка:
Здравствуйте, кубик, Вы писали:

К>Всем привет,


К>Имеем:

К>//////////////////////////////
К>int x;
К>x= 1;
К>for (..) {
К> x=2;
К> vector v(x);
К>}

К>//////////////////////////////

К>Я так понимаю что вектор может сконструируюется в начале скопа, а не по порядку после того как x==2. Так ?

Если x явно присваивается двойке на каждой итерации цикла, то да, может произойти propagation с вынесением из скоупа:
int x = 2;
vector v(x);
for (...) {
...
}


Если же x определяется на каждой итерации цикла в разные значения, то, само собой, вектор останется в теле цикла как локальная сущность.
Re[2]: простой вопрос. неопределенность ?
От: Skipy Rich Россия  
Дата: 17.06.15 10:27
Оценка: +1
Здравствуйте, Mr.Delphist, Вы писали:

К>>for (..) {

К>> x=2;
К>> vector v(x);
К>>}

К>>//////////////////////////////

К>>Я так понимаю что вектор может сконструируюется в начале скопа, а не по порядку после того как x==2. Так ?

MD>Если x явно присваивается двойке на каждой итерации цикла, то да, может произойти propagation с вынесением из скоупа:

MD>
MD>int x = 2;
MD>vector v(x);
MD>for (...) {
MD>...
MD>}
MD>


MD>Если же x определяется на каждой итерации цикла в разные значения, то, само собой, вектор останется в теле цикла как локальная сущность.


Это что это за компилятор может так издевнуться, выбросив пересоздание объекта на каждой итерации? Вынести "x = 2" — это одно. Вынести vector v(x) — это саботаж.
Re[3]: простой вопрос. неопределенность ?
От: Mr.Delphist  
Дата: 17.06.15 13:25
Оценка:
Здравствуйте, Skipy Rich, Вы писали:

SR>Это что это за компилятор может так издевнуться, выбросив пересоздание объекта на каждой итерации? Вынести "x = 2" — это одно. Вынести vector v(x) — это саботаж.


Если инвариант соблюден, то это полностью корректная оптимизация. Само собой, что если конструктор имеет сайд-эффекты (лезет в сеть или к файловой системе, например), то всё останется на своих местах с повторяющимся пересозданием. А так — имеем меньшее число тактов (т.к. инстанциируем один раз), ниже чехарда на хипе и т.п. Профит!
Re[4]: простой вопрос. неопределенность ?
От: Skipy Rich Россия  
Дата: 17.06.15 13:53
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Здравствуйте, Skipy Rich, Вы писали:


SR>>Это что это за компилятор может так издевнуться, выбросив пересоздание объекта на каждой итерации? Вынести "x = 2" — это одно. Вынести vector v(x) — это саботаж.


MD>Если инвариант соблюден, то это полностью корректная оптимизация. Само собой, что если конструктор имеет сайд-эффекты (лезет в сеть или к файловой системе, например), то всё останется на своих местах с повторяющимся пересозданием. А так — имеем меньшее число тактов (т.к. инстанциируем один раз), ниже чехарда на хипе и т.п. Профит!



std::vector<int> v1(2);
for (int j=0; j<2; ++j)
{
    std::vector<int> v2(2);
    assert(v1[0] == v2[0]);
    v1[0] = 22;
    v2[0] = 22;
}


И? Какие ещё нужны сайд-эффекты?
Re[5]: простой вопрос. неопределенность ?
От: Mr.Delphist  
Дата: 17.06.15 15:18
Оценка:
Здравствуйте, Skipy Rich, Вы писали:

SR>Здравствуйте, Mr.Delphist, Вы писали:


MD>>Здравствуйте, Skipy Rich, Вы писали:


SR>>>Это что это за компилятор может так издевнуться, выбросив пересоздание объекта на каждой итерации? Вынести "x = 2" — это одно. Вынести vector v(x) — это саботаж.


MD>>Если инвариант соблюден, то это полностью корректная оптимизация. Само собой, что если конструктор имеет сайд-эффекты (лезет в сеть или к файловой системе, например), то всё останется на своих местах с повторяющимся пересозданием. А так — имеем меньшее число тактов (т.к. инстанциируем один раз), ниже чехарда на хипе и т.п. Профит!


SR>

SR>std::vector<int> v1(2);
SR>for (int j=0; j<2; ++j)
SR>{
SR>    std::vector<int> v2(2);
SR>    assert(v1[0] == v2[0]);
SR>    v1[0] = 22;
SR>    v2[0] = 22;
SR>}
SR>


SR>И? Какие ещё нужны сайд-эффекты?


Зависимость тела цикла от j, например Или ввод-вывод:
std::vector<int> v1(2);
for (int j=0; j<2; ++j)
{
    std::vector<int> v2(2);
    assert(v1[0] == v2[0]);
    v1[0] = 22;
    v2[0] = 22;
    cout << v1[0] << " " << v2[0] << endl;
}



По счастью, времена "измерителей производительности" из разряда "засекаем время, крутим миллион пустых итераций, сравниваем время и вычисляем индекс производительности" давно ушли в прошлое. Скажем, Ваш цикл может быть линеаризован, ввиду малого диапазона j, далее выбрасываются дубликаты (помните сообщения от компилятора "Assignment result is not used"? вот тут они тоже сработают), и получаем совсем другой код, но выдающий ту же самую бизнес-логику. К пуговицам претензии есть? (с)

Компилятор поумнел. Вы действительно считаете, что он, особенно в релизную сборку, будет компилировать всё как есть, без собственных мыслей по этому поводу? Так я Вам даже больше скажу — процессор тоже в этом плане давно не дурак, и может позволять себе вольности с порядком исполнения скомпилированных инструкций, как будет удобнее для загрузки конвейера (CPU reordering).

Да даже дебажные сборки иногда "радуют" фактом пусть неагрессивной, но всё же оптимизации, из-за чего окошко Watches будет показывать печальный warning вместо реального значения.
Re[6]: простой вопрос. неопределенность ?
От: Skipy Rich Россия  
Дата: 17.06.15 15:55
Оценка: +1
Здравствуйте, Mr.Delphist, Вы писали:

MD>Зависимость тела цикла от j, например Или ввод-вывод:

MD>
MD>std::vector<int> v1(2);
MD>for (int j=0; j<2; ++j)
MD>{
MD>    std::vector<int> v2(2);
MD>    assert(v1[0] == v2[0]);
MD>    v1[0] = 22;
MD>    v2[0] = 22;
MD>    cout << v1[0] << " " << v2[0] << endl;
MD>}
MD>



Кажется, мы о разных вещах говорим. В этом примере вторая итерация цикла вылетит на assert, и до ввода-вывода не доберётся. С оптимизацией или без, с сайд-эффектами или без, с процессорным реордерингом или без — вылетит. Потому что.
И если вектор был определен внутри цикла, а оптимизатор выдернет его наружу — это саботаж в случаях, если вектор изменяется внутри цикла, и его содержимое хоть как-то используется. А если нет, то оптимизатор просто может выбросить весь цикл, нет нужды его разворачивать.
Re[2]: простой вопрос. неопределенность ?
От: Erop Россия  
Дата: 17.06.15 21:06
Оценка: -1
Здравствуйте, Mr.Delphist, Вы писали:

MD>Если x явно присваивается двойке на каждой итерации цикла, то да, может произойти propagation с вынесением из скоупа:

MD>
MD>int x = 2;
MD>vector v(x);
MD>for (...) {
MD>...
MD>}
MD>


MD>Если же x определяется на каждой итерации цикла в разные значения, то, само собой, вектор останется в теле цикла как локальная сущность.


А как же деструктор v, который каждую итерацию звать надо?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: простой вопрос. неопределенность ?
От: Mr.Delphist  
Дата: 18.06.15 10:07
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Mr.Delphist, Вы писали:


MD>>Если x явно присваивается двойке на каждой итерации цикла, то да, может произойти propagation с вынесением из скоупа:

MD>>
MD>>int x = 2;
MD>>vector v(x);
MD>>for (...) {
MD>>...
MD>>}
MD>>


MD>>Если же x определяется на каждой итерации цикла в разные значения, то, само собой, вектор останется в теле цикла как локальная сущность.


E>А как же деструктор v, который каждую итерацию звать надо?..


Дык ну батенька, мы же с Вами взрослые люди. Если конструктор, деструктор и прочие должные к вызову вещи не имеют сайд-эффектов и для компилятора выглядят как дублирование одного и того же действия с игнорированием результата — то здравствуй propagation с вынесением из скоупа. А ежели сам вектор v вообще не используется в коде, то и propagation никакого не состоится — "...весь мир насилья мы разрушим до основанья, а затем...".
Re[4]: простой вопрос. неопределенность ?
От: Erop Россия  
Дата: 18.06.15 10:47
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:


MD>Если конструктор, деструктор и прочие должные к вызову вещи не имеют сайд-эффектов и для компилятора выглядят как дублирование одного и того же действия с игнорированием результата — то здравствуй propagation с вынесением из скоупа. А ежели сам вектор v вообще не используется в коде, то и propagation никакого не состоится — "...весь мир насилья мы разрушим до основанья, а затем...".


А сама по себе аллкация разве не сайд-эффект? Я же могу ПТОМ перекрыть operator new, например?
А у нас раздельная компиляция там, все дела?
Конечно сейчас это все компиляторы читят, тут не спорю, но что бы вот так? За исключением некоторых явно перечисленных в стандарте случаев вроде RVO и NRVO, вроде как это несовместимая оптимизация будет?

MD>Дык ну батенька, мы же с Вами взрослые люди.

\
Вот именно. Какие конкретно компиляторы так умеют?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: простой вопрос. неопределенность ?
От: BulatZiganshin  
Дата: 19.06.15 14:26
Оценка:
Здравствуйте, Erop, Вы писали:

E>А сама по себе аллкация разве не сайд-эффект? Я же могу ПТОМ перекрыть operator new, например?

E>А у нас раздельная компиляция там, все дела?

с LTO? вообще не понимаю какая вам разница, если видимое поведение не меняется. ничто не мешает занулять v в начадле каждого цикла, например, вместо создания-уничтожения
Люди, я люблю вас! Будьте бдительны!!!
Re[6]: простой вопрос. неопределенность ?
От: Erop Россия  
Дата: 19.06.15 16:03
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>Вообще не понимаю какая вам разница, если видимое поведение не меняется. ничто не мешает занулять v в начадле каждого цикла, например, вместо создания-уничтожения


Ну таки вызовы кучи -- это сайд-эффект жеж.
Я вполне допускаю, что какие-то компиляторы могут делать такую нестандартную оптимизацию. Но я хотел бы узнать какие так делают в реале...
Я кстати писал это всё в сообщении, на которое ты отвечаешь
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: простой вопрос. неопределенность ?
От: watchmaker  
Дата: 19.06.15 19:09
Оценка: 14 (2)
Здравствуйте, Erop, Вы писали:

E>Но я хотел бы узнать какие так делают в реале...

Из известных компиляторов так делает clang: пример.

E>Я вполне допускаю, что какие-то компиляторы могут делать такую нестандартную оптимизацию.

Если под нестандартностью ты понимаешь не редкость или сложность подобной оптимизации, а отсутствие её в стандарте, то это не так — явное разрешение не выделять память при вычислении new-expression в стандарте есть.

BZ>>Вообще не понимаю какая вам разница, если видимое поведение не меняется. ничто не мешает занулять v в начадле каждого цикла, например, вместо создания-уничтожения


E>Ну таки вызовы кучи -- это сайд-эффект жеж.


Всё же видимое поведение (observable behavior) и сайд-эффекты (side effects) — это немного разные вещи. В стандарте с самой первой версии было разрешено компилятору игнорировать любые сайд-эффекты, если это не влияет на видимое поведение.

До недавнего времени, правда, в стандарте была неоднозначность: с одной стороны состояние внутренней (не volatile) памяти программы не является напрямую наблюдаемым поведением, а с другой стороны в подавляющем числе реализаций операции по выделению памяти периодически приводят к взаимодействию с окружением или ОС (а формально вызов mmap, sbrk, VirtualAlloc или другой функции ОС — это уже наблюдаемое поведение, или подменённый глобальный аллокатор тоже может что-то сложное и наблюдаемое делать).

К счастью, эта неоднозначность была всё же разрешена в n3664 в пользу первой точки зрения.
В целом правильное изменение, я считаю. Всё равно же большинство программ и программистов пользуются глобальным аллокатором как чёрным ящиком (и даже названия реализации его, зачастую, не знает). Так что тут просто узаконивается уже существующий порядок — поведение аллокатора отделяется от поведения программы — он лишь предоставляет память, а как это делается — не важно. Аналогичное положение, кстати говоря, уже давно существует для других функций, в которых семантика ставится выше реализации. Так, например, компилятор спокойно заменит вызов memcpy(u, v, 4) на копирование 4х байт через регистр. Хотя формально программист может заменить функцию memcpy на свою, которая, например, логирует все вызовы в файл или осуществляет какие-то дополнительные проверки и действия (скажем, подобно valgrind). Но компилятор здесь руководствуется именно семантикой (memcpy копирует память) и игнорирует настоящую реализацию.
Re[8]: простой вопрос. неопределенность ?
От: Erop Россия  
Дата: 19.06.15 19:27
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>...отсутствие её в стандарте, то это не так — явное разрешение не выделять память при вычислении new-expression в стандарте есть.


А разве vector<int> v(15); — это new-expression?

W>К счастью, эта неоднозначность была всё же разрешена в n3664 в пользу первой точки зрения.


Спасибо, не знал. Ну и вообще есть много всяких разных отступлений в похожих вопросах, ради удобства оптимизатора.
Скажем то, что можно опускать конструктор копии в конструкциях вроде
std::string s = std::string( "!!!" );

Даже если у него есть и видимое поведение и сайд-эффекты...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: простой вопрос. неопределенность ?
От: watchmaker  
Дата: 19.06.15 20:10
Оценка:
Вышеприведённый ответ был не столько про vector, сколько комментарием к этой строчке:
E>>>Ну таки вызовы кучи -- это сайд-эффект жеж.

W>>...отсутствие её в стандарте, то это не так — явное разрешение не выделять память при вычислении new-expression в стандарте есть.


E>А разве vector<int> v(15); — это new-expression?


Нет. Да с аллокатором по умолчанию внутри vector<int> память выделяется прямым вызовом ::operator new, а не опосредованно через new-expression. Что опять же формально разные вещи. Впрочем для умолчательного аллокатора также есть отдельная оговорка, что не каждый вызов allocate обязан приводить к вызову ::operator new.
Отредактировано 19.06.2015 20:11 watchmaker . Предыдущая версия .
Re[10]: простой вопрос. неопределенность ?
От: Erop Россия  
Дата: 19.06.15 21:28
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Нет. Да с аллокатором по умолчанию внутри vector<int> память выделяется прямым вызовом ::operator new, а не опосредованно через new-expression. Что опять же формально разные вещи. Впрочем для умолчательного аллокатора также есть отдельная оговорка, что не каждый вызов allocate обязан приводить к вызову ::operator new.


Ergo: стандартность такой оптимизации зависит от реализации STL, то есть зависит это неспецифицированное поведение?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: простой вопрос. неопределенность ?
От: cserg  
Дата: 20.06.15 00:30
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>... Если конструктор, деструктор и прочие должные к вызову вещи не имеют сайд-эффектов

А что такое сайд-эффект в данном случае? Запись значения в глобальную переменную в конструкторе — это сайд-эффект?
Вызов из конструктора функции определенной в другой единице трансляции — это сайд-эффект?

MD>и для компилятора выглядят как дублирование одного и того же действия с игнорированием результата

"Выглядят" закончится там, где компилятор обнаружит вызов функции определенной в другой единице трансляции.

MD> — то здравствуй propagation с вынесением из скоупа.

В данном случае propagation называется invariant code motion и компилятор его скорее всего не сделает.
Даже вынос присваивания x=2 можно делать только если цикл исполняется хотя бы один раз, а это не всегда можно проверить.

MD>А ежели сам вектор v вообще не используется в коде,

А ежели цикл не исполняется ни разу, то ваш код не эквивалентен тому, что был у ТС.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.