"Вообще-то, действительное понимание областей видимости объектов и знание правил автоматических вызовов конструкторов и деструкторов, позволяют не горевать особо о мусоросборщиках а-ля Жаба, экономят (порой весьма значительно) доступную память и увеличивают (тоже, зачастую, значительно) быстродействие программы. Правда, обладают этими действительными знанием и пониманием лишь около 5% кодеров на Це-плюсь-плюсе. Остальные 95 - ругаются с компилятором и говорят, что С++ «не работает»." (c) место_чьё_имя_нельзя_упоминать
Рад представить исправленную версию.
Фактически переписанную заново.
Использовал список пулов. Такой подход позволил избавиться от бестолкового копирования, частого выделения памяти, а так-же теперь стек может сам уменьшаться в размере не забывая на всякий случай оставить один пул про запас.
Стек был протестирован с intами и std::string. Ошибок не найдено.
Офк пару вопросов:
Правильно ли реализован метод pop с точки зрения возвращаемого значения?
Как превратить грязный сишный хак в красивый С++ код? Это из метода Resize? смысл в том, что указатель data должен указывать сразу за собой.
/*----------------------------------------------------------------------------*/ /* 6y6yka Engine */ /*----------------------------------------------------------------------------*/ #ifndef _B_STACK_H_ #define _B_STACK_H_ /*----------------------------------------------------------------------------*/ #include <cstdlib> #include <cassert> /*----------------------------------------------------------------------------*/ /* класс bStack */ /* описание: */ /* реализация структуры типа стек */ /* методы: */ /* Push помещает данные в стек */ /* Pop удаляет верхний элемент */ /* Top возвращает ссылку на верхний элемент */ /* Length возвращает количество элементов */ /* Size возвращает объем занимаемой памяти */ /* Resize резервирует память для будущих действий */ /*----------------------------------------------------------------------------*/ template <typename bStackType> class bStack { public: bStack(); ~bStack( ); void Push( const bStackType &item); void Pop( ); bStackType &Top( ) const; int Length( ) const; int Size( ) const; int Resize( unsigned int new_size); private: struct data_pool; data_pool *pool; // список пулов data_pool *old_pool; int allocated; // всего выделено памяти(в итемах) int length; // количество использующихся итемов static const int defsize = 10; bStack( const bStack &); bStack &operator =( const bStack &); }; /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::bStack */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline bStack<bStackType>::bStack( ) { pool = old_pool = 0; allocated = length = 0; } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::~bStack */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline bStack<bStackType>::~bStack( ) { free( old_pool); if( pool) pool->size -= allocated - length; // вычитаем число пустых ячеек while( pool) { for( int i = 0; i < pool->size; i++) pool->data[i].~bStackType( ); old_pool = pool; pool = pool->next; free( old_pool); } } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::Push */ /* описание: */ /* помещает новый элемент в стек */ /* аргументы: */ /* item ссылка на новый элемент */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline void bStack<bStackType>::Push( const bStackType &item) { if( allocated == length) // если стек полон или совсем пуст { if( !old_pool) Resize( allocated * 2); old_pool->next = pool; pool = old_pool; old_pool = 0; allocated += pool->size; } new( &pool->data[pool->size - ( allocated - length++)]) bStackType( item); } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::Pop */ /* описание: */ /* удаляет элемент с верхушки стека */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline void bStack<bStackType>::Pop( ) { int i = pool->size - ( allocated - --length); assert( !( i < 0)); // недопущение противоправных действий. pool->data[i].~bStackType( ); if( !i && pool->next) { if( old_pool) free( old_pool); allocated -= pool->size; old_pool = pool; pool = pool->next; } } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::Top */ /* описание: */ /* возвращает ссылку на верхний элемент */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline bStackType &bStack<bStackType>::Top( ) const { return pool->data[pool->size - ( allocated - ( length - 1))]; } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::Leangth */ /* описание: */ /* возвращает количество элементов в стеке */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline int bStack<bStackType>::Length( ) const { return length; } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::Size */ /* описание: */ /* возвращает максимальное количество элементов. */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline int bStack<bStackType>::Size( ) const { return allocated; } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::Resize */ /* описание: */ /* увеличивает максимально колличество элементов */ /* аргументы: */ /* new_size новый размер в итемах */ /* возвращает: */ /* полный размер стека в итемах */ /*----------------------------------------------------------------------------*/ template <typename bStackType> inline int bStack<bStackType>::Resize( unsigned int new_size) { free( old_pool); old_pool = static_cast<data_pool *>( malloc( sizeof( data_pool) + sizeof( bStackType) * ( new_size ? new_size : new_size = defsize))); old_pool->size = new_size; old_pool->data = reinterpret_cast<bStackType *>( reinterpret_cast<size_t *>( &old_pool->data) + 1); return allocated; } /*----------------------------------------------------------------------------*/ /* bStack<bStackType>::data_pool */ /* описание: */ /* структура для организации списка */ /*----------------------------------------------------------------------------*/ template <typename bStackType> struct bStack<bStackType>::data_pool { int size; // размер куска в итемах data_pool *next; // указатель на предыдущий пулл bStackType *data; // указатель на начало данных }; /*----------------------------------------------------------------------------*/ #endif /* _B_STACK_H_ */
Pokimon
не пойму что такое OldPool...
для описания стека тебе должно хватить 3 указателей..
- начало
- текущий элемент
- конец
когда текущий элемент станет равен концу, стек заполнен и при следующей вставке надо "что-то делать"...
размер буфера = конец - начало
количество элементов = текущий - начало...
или у тебя односвязный список пулов по N элементов??
если так, то реализуй простейший стек на N элементов, так как я показал, потом реализуй список, а потом реализуй свой мегастек через список стеков... в итоге у тебя будет 3 разных контейнера, по цене 2,5...
Pushkoff
> не пойму что такое OldPool...
Здесь хранится освободившаяся память для будущего использования.
Pushkoff
> для описания стека тебе должно хватить 3 указателей
Ну да...
Если бы все было так просто, тема закончилась уже на 1 странице.
Мы живем в век обобщенного программирования.
Поэтому стек должен уметь сам увеличивать свой размер и уменьшать и хранить ЛЮБЫЕ данные.
Мне кажется, что организация стека в виде непрерывного массива ущербна.
Потому, что приходится копировать данные при resize(). А данные они разные. некоторые копируются довольно сложно.
Pushkoff
> или у тебя односвязный список пулов по N элементов??
Односвязный список пулов в каждом по разному элементов и 1 пул сохраняется на всякий случай.
Pokimon
> bStackType Pop();
Саттер негодуэ по поводу "гарантий бессбойности при исключениях".
du_hast
> Саттер негодуэ по поводу "гарантий бессбойности при исключениях".
Не понял?
Какие еще тут исключения?
bad_alloc я не рассматриваю. это фантастика.
И вообще зачем писать загадками?
Просто расскажите как сделать идеальный Pop
Pokimon
> allocated - --length
OH SHI--
Мне кажется, стек накроется, если new_size в Resize будет < 0...
Pushkoff
> для описания стека тебе должно хватить 3 указателей..
> - начало
> - текущий элемент
> - конец
Для описания стека достаточно одного указателя
Pokimon
> Рад представить исправленную версию.
предидущая была лучше, честно
http://pastebin.com/E96bsVJk
AndryBlack
> Для описания стека достаточно одного указателя
тогда это будет односвязный список...
AndryBlack
> http://pastebin.com/E96bsVJk
Вы намекаете, что по этой ссылке реализация стека достойная внимания?
Да это поделие даже не компилируется(по крайней мере студией).
И вообще не конкурент моему стеку ни по скорости ни по простоте использования.
AndryBlack
> предидущая была лучше, честно
Предыдущая была с фатальными ошибками. Не заметит их только слепой.
Voltt
> Мне кажется, стек накроется, если new_size в Resize будет < 0...
щас добавлю asseric
дельный совет.
правка: добавил assert
исправил баг с удалением в деструкторе.
Пошел тестить на скорость.
правка: пока тестил обнаружил, что у std::stack функция Pop просто удаляет элемент и ничего не возвращает.
Сделаю так-же.
Zefick
> в конструкторе сразу выделил память под default_size элементов не дожидаясь вызова Push и сделал бы default_size равным не 1, а сразу, например, 10.
Плохая идея. Отвратительная.
Написал простой тестик.
работа с миллионом строк типа "Medved"
std::stack vs bstack
std::stack : 0.44
bstack : 0.24
Тоесть мой стек, моя задумка, мой способ мышления обыгрывает в 2 раза реализацию из stl
Вобщем я счастлив, поэтому и пишу на форум.
#include <string> #include <iostream> #include <stack> #include <windows.h> #include "b_stack.h" int main() { bStack<std::string> bstack; std::stack<std::string> sstack; LARGE_INTEGER b_1, b_2, s_1, s_2, freq; double br, sr; std::string test = "Medved"; std::string result; QueryPerformanceFrequency( &freq); QueryPerformanceCounter( &b_1); for( int i = 0; i < 1000000; i++) bstack.Push( test); for( int i = 0; i < 1000000; i++) { result = bstack.Top( ); bstack.Pop( ); } for( int i = 0; i < 1000000; i++) { bstack.Push( test); result = bstack.Top( ); bstack.Pop( ); } QueryPerformanceCounter( &b_2); br = ( double)( b_2.QuadPart - b_1.QuadPart)/freq.QuadPart; QueryPerformanceCounter( &s_1); for( int i = 0; i < 1000000; i++) sstack.push( test); for( int i = 0; i < 1000000; i++) { result = sstack.top( ); sstack.pop( ); } for( int i = 0; i < 1000000; i++) { sstack.push( test); result = sstack.top( ); sstack.pop( ); } QueryPerformanceCounter( &s_2); sr = ( double)( s_2.QuadPart - s_1.QuadPart)/freq.QuadPart; std::cout << "bstack result: " << br << std::endl; std::cout << "std::stack result: " << sr << std::endl; system( "pause"); return 0; }
Тема в архиве.