Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 09.01.2016, 17:53   #1
RAFA91
Заблокирован
 
Регистрация: 06.02.2011
Сообщений: 1,999
По умолчанию Резервирование памяти для списка

Добрый день !

Подскажите почему не работает этот кусок ?

Код:
struct point
{
	int x,y;
	point(int _x, int _y) : x(_x),y(_y) {} 
};
]int _tmain(int argc, _TCHAR* argv[])
{
	
	list<point> mylist;
	 mylist.resize(5);   //??????????
	

	return 0;
}

Последний раз редактировалось RAFA91; 09.01.2016 в 17:56.
RAFA91 вне форума Ответить с цитированием
Старый 09.01.2016, 18:00   #2
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

потому что нет конструктора по умолчанию.
http://www.cplusplus.com/reference/list/list/resize/

для связанного списка операция резервирования не имеет смысла ИМХО.
ибо вы забьёте список пустыми значениями(от конструктора по умолчанию), а не резерв некий(да и тогда по-моему лучше вектор уж)
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 09.01.2016, 18:08   #3
RAFA91
Заблокирован
 
Регистрация: 06.02.2011
Сообщений: 1,999
По умолчанию

просто столкнулся с такой проблемой.

нужно отсортировать список по кускам.

алгоритм сортировки не тянет итераторы списка.

поэтому пришлось создать вектор

Код:
vector<point> v(l.begin(),l.end());
и уж с ним мутить кусочную сортировку.
Код:
sort(v.begin(),v.end());
потом опять все передавать назад в список

Код:
copy(v.begin(),v.end(),l.begin());
Код:
v.clear();

Последний раз редактировалось RAFA91; 09.01.2016 в 18:13.
RAFA91 вне форума Ответить с цитированием
Старый 09.01.2016, 18:34   #4
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

А зачем что-то резервировать? В copy можно запихнуть back_inserter.

Как уже написал(на другом форуме), можно соорудить адаптер.
Причем можно соорудить адаптер как для итераторов списка, так и для значений, находящихся в списке (например, если копирование в вектор будет неимоверно дорогим).

Ну и можно, например, использовать splice:
Код:
#include <iostream>
#include <list>
#include <iterator>

int main()
{
    std::list<int> lst {3, 7, 8, 9, 3, 1, 7, 8, 2, 4, 6, 5, 8} ;
    auto iter_beg = lst.begin() ;
    auto iter_end = lst.end() ;
    std::advance(iter_beg, 5) ;
    std::advance(iter_end, -2) ;
    std::list<int> tmp_lst ;
    tmp_lst.splice(tmp_lst.begin(), lst, iter_beg, iter_end) ;
    tmp_lst.sort() ;
    iter_beg = lst.begin() ;
    std::advance(iter_beg, 5) ;
    lst.splice(iter_beg, tmp_lst) ;
    for(auto e: lst)
        std::cout << e << ' ' ;
}
http://rextester.com/QTHU54921

Вот, вынес всё что нужно в отдельную функцию:
Код:
#include <iostream>
#include <list>
#include <iterator>


template<typename T>
void sort_list 
    (
    std::list<T> & lst, //ссылка на список, который будет сортировать
    //и два итератора, которые задают интервал сортировки
    typename std::list<T>::const_iterator begin, 
    typename std::list<T>::const_iterator end 
    )
{
    std::list<T> tmp_lst ;//временный список
    //Определяем расстояние от начала списка до начала интервала сортировки
    typename std::iterator_traits<typename std::list<T>::const_iterator>::difference_type diff = std::distance(lst.cbegin(), begin) ;
    //"Перемещаем(сращиваем)" необходимый кусок списка lst в список tmp_lst 
    //(это делается очень быстро, ибо просто будут меняться несколько указателей, ну и сопутствующие данные, такие как размеры списков).
    tmp_lst.splice(tmp_lst.begin(), lst, begin, end) ;
    //Сортируем временный список
    tmp_lst.sort() ;
    //Берем итератор на начало нашего списка
    typename std::list<T>::const_iterator ins_iterator = lst.begin() ;
    //"Сдвигаем" его до нужной позиции (откуда начинали сортировку)
    std::advance(ins_iterator, diff) ;
    //Ну и сращиваем наш список с временным, причем вставляем кусок туда, где начинали сортировку.
    lst.splice(ins_iterator, tmp_lst) ;
}



int main()
{
    std::list<int> lst {3, 7, 8, 9, 3, 1, 7, 8, 2, 4, 6, 5, 8} ;
    auto iter_beg = lst.begin() ;
    auto iter_end = lst.end() ;
    std::advance(iter_beg, 5) ;
    std::advance(iter_end, -2) ;
    sort_list(lst, iter_beg, iter_end) ;
    for(auto e: lst)
        std::cout << e << ' ' ;
}

Последний раз редактировалось Croessmah; 09.01.2016 в 19:12.
Croessmah вне форума Ответить с цитированием
Старый 10.01.2016, 18:12   #5
RAFA91
Заблокирован
 
Регистрация: 06.02.2011
Сообщений: 1,999
По умолчанию

рад что Вы присутствуете и на этом форуме ))).

адаптер это конечно хорошо только почему бы не воспользоваться другим контейнером ?
RAFA91 вне форума Ответить с цитированием
Старый 10.01.2016, 21:58   #6
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Цитата:
адаптер это конечно хорошо только почему бы не воспользоваться другим контейнером ?
копирование данных в новый контейнер +
сортировка этого контейнера
(если это вектор, то соответственно будет копирование элементов) +
копирование сортированного куска снова в список +
удаление не сортированных старых данных из списка.
Прикиньте, какой это удар по производительности.
Частично потери производительности на больших контейнерах
можно избежать используя всякие прокси-классы, но всё же это будет медленно.

Все эти вопросы решаются splice'ом, который я показал.
Из одного списка данные просто вырезаются (там же тупо переставить указатели),
далее сортировка временного списка (опять же перестановкой указателей),
затем сращиваем сортированный список со старым (и снова тупо указатели поменять).

А теперь представьте себе разницу в производительности этих двух способов,
если один элемент в списке,
допустим, занимает несколько сотен килобайт и копирование его очень дорого обходится.
splice будет в выигрыше практически в любом случае.
А если контейнер очень большой и
кусок для сортировки большой и данные громоздки, то выигрыш просто огромный.

Цитата:
рад что Вы присутствуете и на этом форуме
Здесь присутствую не только я
Croessmah вне форума Ответить с цитированием
Старый 10.01.2016, 22:24   #7
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Для примера немного переделал код.
Теперь у нас не int'ы, а некая структура, которая будет вести лог по созданию элементов:
Код:
struct Test
{
    Test(int x) : x_(x){std::cout << "ctor. x = " << x_ << std::endl ; }
    Test(const Test& src) : x_(src.x_){std::cout << "cctor. x = " << x_ << std::endl ; }
    Test(Test&& src) : x_(src.x_){std::cout << "mctor. x = " << x_ << std::endl ; }
    const Test& operator=(const Test& rhv) { x_=rhv.x_ ; std::cout << "oper=. x = " << x_ << std::endl ; return *this; }
    ~Test(){std::cout << "dtor. x = " << x_ << std::endl ; }
    bool operator<(const Test& rhv) {return x_<rhv.x_ ;}
    int x_ ;
} ;

std::ostream& operator<<(std::ostream& stream, const Test& obj)
{
    stream << obj.x_ << ' ' ;
    return stream ;
}
Сортировать будем диапазон с третьего (по счету) и до предпоследнего элемента (включительно).
итак, алгоритм с копированием в вектор:
Код:
int main()
{
    std::list<Test> lst {3, 7, 8, 9, 3, 1, 7, 8, 2, 4, 6, 5, 8} ;
    auto iter_beg = lst.begin() ;
    auto iter_end = lst.end() ;
    std::advance(iter_beg, 2) ;
    std::advance(iter_end, -1) ;
    
    std::cout << "start algorithm" << std::endl ;
    
    std::vector<Test> tmp_vec(iter_beg, iter_end) ;
    std::sort(tmp_vec.begin(), tmp_vec.end()) ;
    std::move(tmp_vec.begin(), tmp_vec.end(), iter_beg) ;
    
    std::cout << "end algorithm" << std::endl ; 
    for(const auto & e: lst)
        std::cout << e << ' ' ;
    std::cout << std::endl ;
}
http://rextester.com/ULHK36349
Нас интересует только часть вывода между
start algorithm
и
end algorithm
Видите сколько там всяких копирований происходит? (конечно, это тоже можно оптимизировать, но не настолько, чтобы противопоставить splice'ам).
Вот код со splice'ами:
Код:
int main()
{
    std::list<Test> lst {3, 7, 8, 9, 3, 1, 7, 8, 2, 4, 6, 5, 8} ;
    auto iter_beg = lst.begin() ;
    auto iter_end = lst.end() ;
    std::advance(iter_beg, 2) ;
    std::advance(iter_end, -1) ;
    
    std::cout << "start algorithm" << std::endl ; 
    sort_list(lst, iter_beg, iter_end) ;
    std::cout << "end algorithm" << std::endl ; 
    for(const auto & e: lst)
        std::cout << e << ' ' ;
    std::cout << std::endl ;
}
http://rextester.com/OBD79718
И что мы видим? Да просто
Цитата:
start algorithm
end algorithm
ничего!
То есть копирований самих данных нет вообще!
Всё решается перестановкой указателей в самих списках.
Croessmah вне форума Ответить с цитированием
Старый 11.01.2016, 17:52   #8
RAFA91
Заблокирован
 
Регистрация: 06.02.2011
Сообщений: 1,999
По умолчанию

Croessmah благодарю Вас за этот пример. на досуге попытаюсь его прочесть.

то что касается производительности :

мы же не в каменном веке где частота 1 мега. теперь думаю не стоит жалеть память.
RAFA91 вне форума Ответить с цитированием
Старый 11.01.2016, 18:11   #9
RAFA91
Заблокирован
 
Регистрация: 06.02.2011
Сообщений: 1,999
По умолчанию

функция
Код:
advance(it,7);
как я понял это аналог

Код:
for (int i=0; i<7 && it!=mylist1.end(); i++) it++;
?
RAFA91 вне форума Ответить с цитированием
Старый 12.01.2016, 18:33   #10
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Цитата:
как я понял это аналог
http://www.cplusplus.com/reference/iterator/advance/
Зависит от типа итератора.
Для bidirectional итератора - будет использован operator++ для "перемещения на n позиций"
(ну или operator--, в зависимости от того, куда двигаем).
Для random-access итератора - будет использован один operator+
(ну или operator-, в зависимости от того, куда двигаем).

Ваш цикл не верен.
У advance есть только итератор и кол-во позиций, на которые двигаем.
Доступа к самому списку у него нет, так что mylist1.end() не прокатит.

Цитата:
теперь думаю не стоит жалеть память.
Создатели некоторых приложений, видимо, тоже так думают...
Поэтому их тормознутое УГ на помойке софта валяется.
Croessmah вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Отключить резервирование места в IdHTTP kangreon Работа с сетью в Delphi 3 21.03.2018 11:02
Blowfish (резервирование дополнительного байта для блока, говорящий о длине блока) ITdocer Общие вопросы C/C++ 0 21.05.2014 15:40
Очистка списка имен UserForm из памяти iNataliya Microsoft Office Excel 4 30.08.2013 00:21
Удаление связного списка из памяти Mahin Общие вопросы C/C++ 3 13.07.2012 10:10
Программа для тестирования памяти, тестирование ячеек памяти Hunter557 Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 0 30.01.2011 19:20