В нём от нуля до любого числа элементов
Нужно запомнить текущую позицию
Потом вставить рандомное число элементов
И в конце получить итератор на первый рандомный вставленный элемент
В процедуру, которая вставляет рандомное число элементов у нас нет доступа
Как?
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() для вставки одного элемента.
Там идёт сложный расчёт с большим числом ветвлений
Первый элемент добавляется в большом количестве мест
Не хочется усложнять код