std::list Сохранить позицию
От: TailWind  
Дата: 18.08.19 14:13
Оценка:
Есть list<ULONG>

В нём от нуля до любого числа элементов
Нужно запомнить текущую позицию
Потом вставить рандомное число элементов
И в конце получить итератор на первый рандомный вставленный элемент

В процедуру, которая вставляет рандомное число элементов у нас нет доступа
Как?

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
Re: std::list Сохранить позицию
От: Vamp Россия  
Дата: 18.08.19 14:38
Оценка:
Здравствуйте, TailWind, Вы писали:

q= List.back();
qq = q + 1;


Или я чего-то не понимаю?
Да здравствует мыло душистое и веревка пушистая.
Re[2]: std::list Сохранить позицию
От: TailWind  
Дата: 18.08.19 15:02
Оценка:
Здравствуйте, Vamp, Вы писали:

V>Здравствуйте, TailWind, Вы писали:


V>
V>q= List.back();
V>qq = q + 1;

V>


V>Или я чего-то не понимаю?


reference back();
Returns a reference to the last element.


Возвращает reference, а не iterator
Re[3]: std::list Сохранить позицию
От: Vamp Россия  
Дата: 18.08.19 15:06
Оценка: 4 (1)
TW>Возвращает reference, а не iterator


И то верно. Тогда не back(), а end() — 1.
Да здравствует мыло душистое и веревка пушистая.
Re[4]: std::list Сохранить позицию
От: TailWind  
Дата: 18.08.19 15:18
Оценка:
V>И то верно. Тогда не back(), а end() — 1.
И как мне из него получить итератор на "4"?

List.end()-- возвращает итератор на "6"

Хотелось бы рабочий пример
Который учитывает, что изначально в лист мог быть пустым
Отредактировано 18.08.2019 15:24 TailWind . Предыдущая версия . Еще …
Отредактировано 18.08.2019 15:19 TailWind . Предыдущая версия .
Re[5]: std::list Сохранить позицию
От: watchmaker  
Дата: 18.08.19 15:40
Оценка:
Здравствуйте, 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) и передавать в недоступный код всегда пустой список, а потом мгновенно их объединять. Тогда отдельно рассматривать случай пустого исходного списка не придётся.
Отредактировано 18.08.2019 15:41 watchmaker . Предыдущая версия .
Re[6]: std::list Сохранить позицию
От: TailWind  
Дата: 18.08.19 16:01
Оценка:
W>Но такой код, действительно, не сработает для пустого списка.
W>Но ты можешь обработать этот случай отдельно
Ну это понятно
Я думал, может есть какой красивый вариант "в одну строчку"

"добавить пустой элемент", потом удалить интересная идея
Re[5]: std::list Сохранить позицию
От: Vamp Россия  
Дата: 18.08.19 16:05
Оценка:
Здравствуйте, TailWind, Вы писали:

TW>И как мне из него получить итератор на "4"?

Очевидно инкрементировав его

TW>Хотелось бы рабочий пример

TW>Который учитывает, что изначально в лист мог быть пустым
Этого в исходной задаче не было. Если лист может быть пустым, то можно сначала проверить не пуст ли он, и если пуст, то потом итератор на начало будет просто begin().
Да здравствует мыло душистое и веревка пушистая.
Re[7]: std::list Сохранить позицию
От: a7d3  
Дата: 18.08.19 16:38
Оценка: +2
Здравствуйте, TailWind, Вы писали:

W>>Но такой код, действительно, не сработает для пустого списка.

W>>Но ты можешь обработать этот случай отдельно
TW>Ну это понятно
TW>Я думал, может есть какой красивый вариант "в одну строчку"

TW>"добавить пустой элемент", потом удалить интересная идея


Если в коде соблюдается exception safety, то в процедуру изменяющую список надо отдавать специальный пустой std::list, с которым выполнять действия что планировались посредством итератора на сохраненное положение. А после этого уже через splice добавлять в уже имевшийся ранее список. Это и красивее, и позволяет реализовать транзакционность при возникновении исключения при работе со вставленными элементами.
Re[6]: std::list Сохранить позицию
От: TailWind  
Дата: 18.08.19 18:02
Оценка:
TW>>И как мне из него получить итератор на "4"?
V>Очевидно инкрементировав его

Прошу прощения
Я не разглядел -1
Думал там просто List.end()

V>>И то верно. Тогда не back(), а end() — 1.


Проблема в том, из List.end() не сделать 4
А если лист изначально пуст, то end()-- вывалится с ошибкой
И нужно писать дополнительный код

Место становится трудно читаемым

Придётся выносить в отдельную процедуру или класс
Чтобы было быстро понятно, что происходит при чтении кода через много лет
Отредактировано 18.08.2019 18:03 TailWind . Предыдущая версия .
Re[6]: std::list Сохранить позицию
От: TailWind  
Дата: 18.08.19 18:49
Оценка:
Разобрался
Спасибо большое, за помощь!

list<ULONG> List;
//
List.push_back(1);
List.push_back(2);
List.push_back(3);
//
list<ULONG>::iterator q = List.end();  if (!List.empty()) q--;
//
List.push_back(4);
List.push_back(5);
List.push_back(6);
//
if (q == List.end()) q = List.begin();  // лист был пуст
else                 q++;               // в листе были элементы
////////////////////////////////////////////////////////////
// Показываем чему равен q
// выводит:
// q = 4
////////////////////////////////////////////////////////////
if (q == List.begin()) Log->printf(L"q = begin\n");
if (q == List.end())   Log->printf(L"q = end\n");
//
for (list<ULONG>::iterator i=List.begin(); i!=List.end(); i++)
{
  if (i == q) Log->printf(L"q = %d\n", *i);
}



list<ULONG> List;
//
/*
List.push_back(1);
List.push_back(2);
List.push_back(3);
*/
list<ULONG>::iterator q = List.end();  if (!List.empty()) q--;
//
List.push_back(4);
List.push_back(5);
List.push_back(6);
//
if (q == List.end()) q = List.begin();  // лист был пуст
else                 q++;               // в листе были элементы
////////////////////////////////////////////////////////////
// Показываем чему равен q
// выводит:
// q = begin
// q = 4
////////////////////////////////////////////////////////////
if (q == List.begin()) Log->printf(L"q = begin\n");
if (q == List.end())   Log->printf(L"q = end\n");
//
for (list<ULONG>::iterator i=List.begin(); i!=List.end(); i++)
{
  if (i == q) Log->printf(L"q = %d\n", *i);
}
Отредактировано 18.08.2019 18:52 TailWind . Предыдущая версия . Еще …
Отредактировано 18.08.2019 18:52 TailWind . Предыдущая версия .
Отредактировано 18.08.2019 18:51 TailWind . Предыдущая версия .
Re: std::list Сохранить позицию
От: AleksandrN Россия  
Дата: 18.08.19 22:32
Оценка:
Здравствуйте, 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>Как?

Что эта функция делает, кроме того, что элементы вставляет?
Re[2]: std::list Сохранить позицию
От: TailWind  
Дата: 18.08.19 22:41
Оценка:
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"
}
Отредактировано 18.08.2019 22:46 TailWind . Предыдущая версия .
Re[3]: std::list Сохранить позицию
От: AleksandrN Россия  
Дата: 18.08.19 23:16
Оценка:
Здравствуйте, 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;
}
Отредактировано 19.08.2019 5:29 AleksandrN . Предыдущая версия . Еще …
Отредактировано 18.08.2019 23:20 AleksandrN . Предыдущая версия .
Re[4]: std::list Сохранить позицию
От: TailWind  
Дата: 19.08.19 00:30
Оценка:
AN>Используемый компилятор C++11 поддерживает?
Нет

Но не в этом суть
Суть в том, что в f1 и f2 у нас нет доступа
Re: std::list Сохранить позицию
От: rg45 СССР  
Дата: 19.08.19 07:30
Оценка:
Здравствуйте, 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);


Ну, разумеется, это только в том случае, если мы уверены, что внешняя процедура добавляет элементы только в конец списка, а не в начало и не в середину
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 19.08.2019 7:39 rg45 . Предыдущая версия .
Re[5]: std::list Сохранить позицию
От: AleksandrN Россия  
Дата: 19.08.19 10:41
Оценка:
Здравствуйте, TailWind, Вы писали:

TW>Суть в том, что в f1 и f2 у нас нет доступа


Что значит "нет доступа"? Функция библиотечная и исходников нет?

Если функция только вставляет элементы, то лучше написать вместо неё свою функцию, которая вставляет несколько элементов и возвращает итератор на 1-й из них. И до C++11 можно использовать insert() для вставки одного элемента.
Re[6]: std::list Сохранить позицию
От: TailWind  
Дата: 19.08.19 14:11
Оценка:
AN>Что значит "нет доступа"? Функция библиотечная и исходников нет?

AN>Если функция только вставляет элементы, то лучше написать вместо неё свою функцию, которая вставляет несколько элементов и возвращает итератор на 1-й из них. И до C++11 можно использовать insert() для вставки одного элемента.


Там идёт сложный расчёт с большим числом ветвлений
Первый элемент добавляется в большом количестве мест
Не хочется усложнять код
Re[7]: std::list Сохранить позицию
От: a7d3  
Дата: 19.08.19 15:42
Оценка:
TW>Там идёт сложный расчёт с большим числом ветвлений
TW>Первый элемент добавляется в большом количестве мест
TW>Не хочется усложнять код

Тогда через пустой список и потом slice – std::list Сохранить позицию
Re[8]: std::list Сохранить позицию
От: TailWind  
Дата: 19.08.19 17:56
Оценка:
A>Тогда через пустой список и потом slice – std::list Сохранить позицию
Да я видел ваше решение — интересное

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