Сообщение Re[2]: Эффективный простреливатель ног C++ 11, 14, 17, 20 от 02.01.2021 18:43
Изменено 04.01.2021 20:33 watchmaker
Re[2]: Эффективный простреливатель ног C++ 11, 14, 17, 20
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, Тёмчик, Вы писали:
Тё>>С++11 emplace_back
Тё>>
Тё>>Думаете, результат будет [123, 123]? Think again.
N>Слушай, а что будет? Я проверил на Ideone, всё норм.
С++ гарантирует, что будет вектор из двух элементов [123, 123]. Релевантная ссылка: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526
Но это хороший тест, на котором ломаются многие самодельные аналоги std::vector.
В них относительно часто встречается баг наивной реализация вставки, устроенная примерно так:
где reserve работает так:
При аккуратном рассмотрении, видно, что если аргумент emplace_back (или push_back) ссылался на собственный элемент вектора и если при его вставке произошла реаллокация, то после пункта 2, элемент, который нужно было скопировать и вставить, окажется уже разрушенным. И вставлять станет нечего.
(и даже говорят, в некоторых древних версиях STL встречался этот баг)
Надёжный std::vector написать сложно :)
На самом деле в реализациях std::vector приходится учитывать множество подобных нюансов, которые не должны приводить к несогласованному состоянию когда подобный код напишут или когда во время переноса одного из элементов вылетит исключение.
ЗЫ. Если интересно, часто эту проблему решают так: при реаллокации сначала выделяют новый буфер, создают в нём сразу новый элемент, и лишь затем переносят в новый буфер старые элементы. То есть в emplace_back нельзя использовать reserve непосредственно, и нужно элементы обрабатывать в особом порядке (сначала новый, потом старые, а не наоборот), что при первом прочтении выглядит немного странным.
N>Здравствуйте, Тёмчик, Вы писали:
Тё>>С++11 emplace_back
Тё>>
Тё>>std::vector<int> v;
Тё>>v.emplace_back(123);
Тё>>v.emplace_back(v[0]);
Тё>>
Тё>>Думаете, результат будет [123, 123]? Think again.
N>Слушай, а что будет? Я проверил на Ideone, всё норм.
С++ гарантирует, что будет вектор из двух элементов [123, 123]. Релевантная ссылка: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526
Но это хороший тест, на котором ломаются многие самодельные аналоги std::vector.
В них относительно часто встречается баг наивной реализация вставки, устроенная примерно так:
1. Проверить size() < capacity(). Если выполнено перейти к пункту 3.
2. Позвать reserve(size() × 2)
3. Вызвать in-place конструктор для нового элемента по смещению size();
4. Сделать ++size;
где reserve работает так:
1. Выделяет новый буфер;
2. Переносит в него элементы из текущего буфера;
3. Разрушает элементы в старом буфере и освобождает память;
При аккуратном рассмотрении, видно, что если аргумент emplace_back (или push_back) ссылался на собственный элемент вектора и если при его вставке произошла реаллокация, то после пункта 2, элемент, который нужно было скопировать и вставить, окажется уже разрушенным. И вставлять станет нечего.
(и даже говорят, в некоторых древних версиях STL встречался этот баг)
Надёжный std::vector написать сложно :)
На самом деле в реализациях std::vector приходится учитывать множество подобных нюансов, которые не должны приводить к несогласованному состоянию когда подобный код напишут или когда во время переноса одного из элементов вылетит исключение.
ЗЫ. Если интересно, часто эту проблему решают так: при реаллокации сначала выделяют новый буфер, создают в нём сразу новый элемент, и лишь затем переносят в новый буфер старые элементы. То есть в emplace_back нельзя использовать reserve непосредственно, и нужно элементы обрабатывать в особом порядке (сначала новый, потом старые, а не наоборот), что при первом прочтении выглядит немного странным.
Re[2]: Эффективный простреливатель ног C++ 11, 14, 17, 20
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, Тёмчик, Вы писали:
Тё>>С++11 emplace_back
Тё>>
Тё>>Думаете, результат будет [123, 123]? Think again.
N>Слушай, а что будет? Я проверил на Ideone, всё норм.
С++ гарантирует, что будет вектор из двух элементов [123, 123]. Релевантная ссылка: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526
Но это хороший тест, на котором ломаются многие самодельные аналоги std::vector.
В них относительно часто встречается наивная реализация вставки, устроенная примерно так:
где reserve работает так:
При аккуратном рассмотрении, видно, что если аргумент emplace_back (или push_back) ссылался на собственный элемент вектора и если при его вставке произошла реаллокация, то после пункта 2, элемент, который нужно было скопировать и вставить, окажется уже разрушенным. И вставлять станет нечего.
(и даже говорят, в некоторых древних версиях STL встречался этот баг)
Надёжный std::vector написать сложно :)
На самом деле в реализациях std::vector приходится учитывать множество подобных нюансов, которые не должны приводить к несогласованному состоянию когда подобный код напишут или когда во время переноса одного из элементов вылетит исключение.
ЗЫ. Если интересно, часто эту проблему решают так: при реаллокации сначала выделяют новый буфер, создают в нём сразу новый элемент, и лишь затем переносят в новый буфер старые элементы. То есть в emplace_back нельзя использовать reserve непосредственно, и нужно элементы обрабатывать в особом порядке (сначала новый, потом старые, а не наоборот), что при первом прочтении выглядит немного странным.
N>Здравствуйте, Тёмчик, Вы писали:
Тё>>С++11 emplace_back
Тё>>
Тё>>std::vector<int> v;
Тё>>v.emplace_back(123);
Тё>>v.emplace_back(v[0]);
Тё>>
Тё>>Думаете, результат будет [123, 123]? Think again.
N>Слушай, а что будет? Я проверил на Ideone, всё норм.
С++ гарантирует, что будет вектор из двух элементов [123, 123]. Релевантная ссылка: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526
Но это хороший тест, на котором ломаются многие самодельные аналоги std::vector.
В них относительно часто встречается наивная реализация вставки, устроенная примерно так:
1. Проверить size() < capacity(). Если выполнено перейти к пункту 3.
2. Позвать reserve(size() × 2)
3. Вызвать in-place конструктор для нового элемента по смещению size();
4. Сделать ++size;
где reserve работает так:
1. Выделяет новый буфер;
2. Переносит в него элементы из текущего буфера;
3. Разрушает элементы в старом буфере и освобождает память;
При аккуратном рассмотрении, видно, что если аргумент emplace_back (или push_back) ссылался на собственный элемент вектора и если при его вставке произошла реаллокация, то после пункта 2, элемент, который нужно было скопировать и вставить, окажется уже разрушенным. И вставлять станет нечего.
(и даже говорят, в некоторых древних версиях STL встречался этот баг)
Надёжный std::vector написать сложно :)
На самом деле в реализациях std::vector приходится учитывать множество подобных нюансов, которые не должны приводить к несогласованному состоянию когда подобный код напишут или когда во время переноса одного из элементов вылетит исключение.
ЗЫ. Если интересно, часто эту проблему решают так: при реаллокации сначала выделяют новый буфер, создают в нём сразу новый элемент, и лишь затем переносят в новый буфер старые элементы. То есть в emplace_back нельзя использовать reserve непосредственно, и нужно элементы обрабатывать в особом порядке (сначала новый, потом старые, а не наоборот), что при первом прочтении выглядит немного странным.