В нём от нуля до любого числа элементов
Нужно запомнить текущую позицию
Потом вставить рандомное число элементов
И в конце получить итератор на первый рандомный вставленный элемент
В процедуру, которая вставляет рандомное число элементов у нас нет доступа
Как?
List.push_back(1);
List.push_back(2);
List.push_back(3);
//
list<ULONG>::iterator q = ?
//
{
// сюда нет доступа
List.push_back(4);
List.push_back(5);
List.push_back(6);
}
//
list<ULONG>::iterator qq = итератор на 4
Здравствуйте, TailWind, Вы писали:
V>>И то верно. Тогда не back(), а end() — 1. TW>И как мне из него получить итератор на "4"?
Думаю, Vamp намекал на такое решение:
auto q = std::prev(List.end());
...
auto qq = std::next(q);
TW>Который учитывает, что изначально в лист мог быть пустым
Но такой код, действительно, не сработает для пустого списка.
Но ты можешь обработать этот случай отдельно
Например, запомнить, что изначально список был пуст, а значит вместо std::next(q) нужно взять List.begin().
Либо можно воспользоваться одним из трюков по работе со списками: например, вставить заголовочный элемент; или воспользоваться возможностью сделать splice за O(1) и передавать в недоступный код всегда пустой список, а потом мгновенно их объединять. Тогда отдельно рассматривать случай пустого исходного списка не придётся.
W>Но такой код, действительно, не сработает для пустого списка. W>Но ты можешь обработать этот случай отдельно
Ну это понятно
Я думал, может есть какой красивый вариант "в одну строчку"
"добавить пустой элемент", потом удалить интересная идея
Здравствуйте, TailWind, Вы писали:
TW>И как мне из него получить итератор на "4"?
Очевидно инкрементировав его
TW>Хотелось бы рабочий пример TW>Который учитывает, что изначально в лист мог быть пустым
Этого в исходной задаче не было. Если лист может быть пустым, то можно сначала проверить не пуст ли он, и если пуст, то потом итератор на начало будет просто begin().
Здравствуйте, TailWind, Вы писали:
W>>Но такой код, действительно, не сработает для пустого списка. W>>Но ты можешь обработать этот случай отдельно TW>Ну это понятно TW>Я думал, может есть какой красивый вариант "в одну строчку"
TW>"добавить пустой элемент", потом удалить интересная идея
Если в коде соблюдается exception safety, то в процедуру изменяющую список надо отдавать специальный пустой std::list, с которым выполнять действия что планировались посредством итератора на сохраненное положение. А после этого уже через splice добавлять в уже имевшийся ранее список. Это и красивее, и позволяет реализовать транзакционность при возникновении исключения при работе со вставленными элементами.
Здравствуйте, TailWind, Вы писали:
TW>Есть list<ULONG>
TW>В нём от нуля до любого числа элементов TW>Нужно запомнить текущую позицию TW>Потом вставить рандомное число элементов TW>И в конце получить итератор на первый рандомный вставленный элемент
Может быть подойдёт использование insert() или emplace() вместо push_back()?
List.push_back(1);
List.push_back(2);
std::list<int>::iterator it = List.insert(List.end(), 3);
{
// сюда нет доступа
List.push_back(4);
List.push_back(5);
List.push_back(6);
}
it++;
std::cout << "*it = " << *it << '\n';
TW>В процедуру, которая вставляет рандомное число элементов у нас нет доступа TW>Как?
Что эта функция делает, кроме того, что элементы вставляет?
AN>Что эта функция делает, кроме того, что элементы вставляет?
Только элементы вставляет:
list<ULONG> List;
void f1()
{
// вставляем 0 или больше элементов
List.push_back(1);
List.push_back(2);
List.push_back(3);
}
void f2()
{
// вставляем 0 или больше элементов
List.push_back(4);
List.push_back(5);
List.push_back(6);
}
main()
{
f1();
// тут можно что-то сделать
f2();
// тут нужно получить итератор на элемент "4"
}
Здравствуйте, TailWind, Вы писали:
AN>>Что эта функция делает, кроме того, что элементы вставляет? TW>Только элементы вставляет:
Используемый компилятор C++11 поддерживает?
#include <list>
#include <iostream>
typedef unsigned long ULONG;
std::list<ULONG> List;
int main()
{
std::list<ULONG>::iterator it = List.insert( List.end(), {1, 2, 3} );
std::cout << "*it = " << *it << '\n';
// тут можно что-то сделать
it = List.insert( List.end(), {4, 5, 6} );
// тут нужно получить итератор на элемент "4"
std::cout << "*it = " << *it << '\n';
return 0;
}
Здравствуйте, TailWind, Вы писали:
TW>Есть list<ULONG>
TW>В нём от нуля до любого числа элементов TW>Нужно запомнить текущую позицию TW>Потом вставить рандомное число элементов TW>И в конце получить итератор на первый рандомный вставленный элемент
TW>В процедуру, которая вставляет рандомное число элементов у нас нет доступа TW>Как?
На правах шутки:
const auto Before = List.insert(List.end(), 0);
// Call to the external function inserting elements
populate(List);
const auto Begin = List.erase(Before);
Ну, разумеется, это только в том случае, если мы уверены, что внешняя процедура добавляет элементы только в конец списка, а не в начало и не в середину
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, TailWind, Вы писали:
TW>Суть в том, что в f1 и f2 у нас нет доступа
Что значит "нет доступа"? Функция библиотечная и исходников нет?
Если функция только вставляет элементы, то лучше написать вместо неё свою функцию, которая вставляет несколько элементов и возвращает итератор на 1-й из них. И до C++11 можно использовать insert() для вставки одного элемента.
AN>Что значит "нет доступа"? Функция библиотечная и исходников нет?
AN>Если функция только вставляет элементы, то лучше написать вместо неё свою функцию, которая вставляет несколько элементов и возвращает итератор на 1-й из них. И до C++11 можно использовать insert() для вставки одного элемента.
Там идёт сложный расчёт с большим числом ветвлений
Первый элемент добавляется в большом количестве мест
Не хочется усложнять код
Здравствуйте, TailWind, Вы писали:
A>>Тогда через пустой список и потом slice – std::list Сохранить позицию TW>Да я видел ваше решение — интересное
TW>У меня, к сожалению, не получится применить TW>Так как функции, которые добавляют новые элементы анализируют значения существующих
А что на счет exception safety?
Это не логично — вносить изменения в объектную модель без возможности откатить неудачную транзакцию, если провалился один из этапов.
A>А что на счет exception safety? A>Это не логично — вносить изменения в объектную модель без возможности откатить неудачную транзакцию, если провалился один из этапов.
Такого не должно быть
Если выполнились все условия, код добавляет элементы в лист и возвращает true
Если не выполнились, ничего не делает, и возвращает false
Здравствуйте, TailWind, Вы писали:
A>>А что на счет exception safety? A>>Это не логично — вносить изменения в объектную модель без возможности откатить неудачную транзакцию, если провалился один из этапов. TW>Такого не должно быть
TW>Если выполнились все условия, код добавляет элементы в лист и возвращает true TW>Если не выполнились, ничего не делает, и возвращает false
Каковы гарантии безопасности по исключениям?
Каким образом возвращать список в изначальное состояние при досрочном завершении его обработки (из-за выскакивания исключения в каком-либо месте)?
Пример №1.
Есть библиотечная функция/процедура добавляющая какие-то элементы в список. Если она споткнется на каком-то этапе, то ее выполнение завершится досрочно — из нее вылетит исключение. В список она при этом успеет добавить лишь некоторые из элементов, но далеко не все, какие должна была бы. Каков сценарий развития событий дальше? Программа аварийно завершается прекращая какую-либо работу?
Пример №2.
Библиотечная функция отработала благополучно, но споткнулся тот код, отвечающий за завершающие действия (зная в какое место списка эта функция добавляла элементы). Список опять получился не в том состоянии, в каком должен был бы отработай все штатно. Тогда вся программа целиком подлежит аварийной остановке?
A>Каковы гарантии безопасности по исключениям? A>Тогда вся программа целиком подлежит аварийной остановке?
Вы интересную тему поднимаете
Но я, не настолько хороший программист чтобы её поддержать
Скорее всего сюжет будет следующий: функция была вызвана по нажатию кнопки или во время отрисовки окна. Там я забыл поставить try-catch. Исключение пойдёт в модуль с winapi, где будет поймано, выведено на экран и программа благополучно исчезнет с экрана
Здравствуйте, TailWind, Вы писали:
A>>Каковы гарантии безопасности по исключениям? A>>Тогда вся программа целиком подлежит аварийной остановке?
TW>Вы интересную тему поднимаете TW>Но я, не настолько хороший программист чтобы её поддержать
TW>Скорее всего сюжет будет следующий: функция была вызвана по нажатию кнопки или во время отрисовки окна. Там я забыл поставить try-catch. Исключение пойдёт в модуль с winapi, где будет поймано, выведено на экран и программа благополучно исчезнет с экрана
Это так называемый «fail fast» — терпимо и актуально не для всех приложений.
Используется в тех случаях, когда проще быстро перезапустить софтину после «падения». Иногда дешевле/проще именно так, чем реализовывать корректную работу с исключениями в плане транзакционности изменений объектной модели внутри софтины (во избежание некорректных, частичных состояний).
Здравствуйте, TailWind, Вы писали:
TW>Есть list<ULONG>
TW>В нём от нуля до любого числа элементов TW>Нужно запомнить текущую позицию TW>Потом вставить рандомное число элементов TW>И в конце получить итератор на первый рандомный вставленный элемент
TW>В процедуру, которая вставляет рандомное число элементов у нас нет доступа TW>Как?
Извиняюсь за поздний ответ!
Для списка целых чисел использовать std::list — накладно по памяти.
Нужна какая-то страничная структура. Возможно, подойдёт одностраничная — std::vector!
Для коротких списков операции вставки-удаления из середины — для вектора не так уж дороги. А для длинных — мы будем платить цену за хранение, и ещё неизвестно, что выйдет дешевле.