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 Сохранить позицию
Да я видел ваше решение — интересное

У меня, к сожалению, не получится применить
Так как функции, которые добавляют новые элементы анализируют значения существующих
Re[9]: std::list Сохранить позицию
От: a7d3  
Дата: 19.08.19 18:06
Оценка: +1
Здравствуйте, TailWind, Вы писали:

A>>Тогда через пустой список и потом slice – std::list Сохранить позицию

TW>Да я видел ваше решение — интересное

TW>У меня, к сожалению, не получится применить

TW>Так как функции, которые добавляют новые элементы анализируют значения существующих

А что на счет exception safety?
Это не логично — вносить изменения в объектную модель без возможности откатить неудачную транзакцию, если провалился один из этапов.
Re[10]: std::list Сохранить позицию
От: TailWind  
Дата: 19.08.19 18:42
Оценка:
A>А что на счет exception safety?
A>Это не логично — вносить изменения в объектную модель без возможности откатить неудачную транзакцию, если провалился один из этапов.
Такого не должно быть

Если выполнились все условия, код добавляет элементы в лист и возвращает true
Если не выполнились, ничего не делает, и возвращает false
Re[11]: std::list Сохранить позицию
От: a7d3  
Дата: 19.08.19 20:10
Оценка:
Здравствуйте, TailWind, Вы писали:

A>>А что на счет exception safety?

A>>Это не логично — вносить изменения в объектную модель без возможности откатить неудачную транзакцию, если провалился один из этапов.
TW>Такого не должно быть

TW>Если выполнились все условия, код добавляет элементы в лист и возвращает true

TW>Если не выполнились, ничего не делает, и возвращает false

Каковы гарантии безопасности по исключениям?
Каким образом возвращать список в изначальное состояние при досрочном завершении его обработки (из-за выскакивания исключения в каком-либо месте)?

Пример №1.
Есть библиотечная функция/процедура добавляющая какие-то элементы в список. Если она споткнется на каком-то этапе, то ее выполнение завершится досрочно — из нее вылетит исключение. В список она при этом успеет добавить лишь некоторые из элементов, но далеко не все, какие должна была бы. Каков сценарий развития событий дальше? Программа аварийно завершается прекращая какую-либо работу?

Пример №2.
Библиотечная функция отработала благополучно, но споткнулся тот код, отвечающий за завершающие действия (зная в какое место списка эта функция добавляла элементы). Список опять получился не в том состоянии, в каком должен был бы отработай все штатно. Тогда вся программа целиком подлежит аварийной остановке?
Re[12]: std::list Сохранить позицию
От: TailWind  
Дата: 20.08.19 14:57
Оценка:
A>Каковы гарантии безопасности по исключениям?
A>Тогда вся программа целиком подлежит аварийной остановке?

Вы интересную тему поднимаете
Но я, не настолько хороший программист чтобы её поддержать

Скорее всего сюжет будет следующий: функция была вызвана по нажатию кнопки или во время отрисовки окна. Там я забыл поставить try-catch. Исключение пойдёт в модуль с winapi, где будет поймано, выведено на экран и программа благополучно исчезнет с экрана
Re[13]: std::list Сохранить позицию
От: a7d3  
Дата: 21.08.19 11:26
Оценка:
Здравствуйте, TailWind, Вы писали:

A>>Каковы гарантии безопасности по исключениям?

A>>Тогда вся программа целиком подлежит аварийной остановке?

TW>Вы интересную тему поднимаете

TW>Но я, не настолько хороший программист чтобы её поддержать

TW>Скорее всего сюжет будет следующий: функция была вызвана по нажатию кнопки или во время отрисовки окна. Там я забыл поставить try-catch. Исключение пойдёт в модуль с winapi, где будет поймано, выведено на экран и программа благополучно исчезнет с экрана


Это так называемый «fail fast» — терпимо и актуально не для всех приложений.
Используется в тех случаях, когда проще быстро перезапустить софтину после «падения». Иногда дешевле/проще именно так, чем реализовывать корректную работу с исключениями в плане транзакционности изменений объектной модели внутри софтины (во избежание некорректных, частичных состояний).
Re: std::list Сохранить позицию
От: Кодт Россия  
Дата: 06.09.19 10:10
Оценка:
Здравствуйте, TailWind, Вы писали:

TW>Есть list<ULONG>


TW>В нём от нуля до любого числа элементов

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

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

TW>Как?

Извиняюсь за поздний ответ!

Для списка целых чисел использовать std::list — накладно по памяти.
Нужна какая-то страничная структура. Возможно, подойдёт одностраничная — std::vector!
Для коротких списков операции вставки-удаления из середины — для вектора не так уж дороги. А для длинных — мы будем платить цену за хранение, и ещё неизвестно, что выйдет дешевле.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.