Форум программистов, компьютерный форум CyberForum.ru

C++

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 5.00
SatanaXIII
Супер-модератор
Эксперт С++
5578 / 2612 / 239
Регистрация: 01.11.2011
Сообщений: 6,422
Завершенные тесты: 1
#1

Надзиратель томагавков или что за велосипед я изобрел? - C++

03.03.2014, 11:29. Просмотров 477. Ответов 2
Метки нет (Все метки)

Название: She2.jpg
Просмотров: 88

Размер: 10.5 Кб
She's alive!

Господа, в общем вдохновился я темой programina про статические поля класса и решил создать что-то похожее на сборщик мусора. По скольку я придерживаюсь мнения, что порою лучше сперва самому поковыряться, а потом уже почитать как правильно надо было сделать, то вот такой у меня получился уродец.

Долго думал куда можно его применить в качестве примера. Придумал - класс-томагавк. Смысл в чем: какая-нибудь гипотетическая игрушка, где индеец бросает томагавки. Функция main тут имитирует само интерактивное бросание неизвестного количества томагавков. При каждом броске создается отдельный экземпляр класса томагавк, содержащий какие-либо свойства и методы (как он будет там вращаться, с какой скоростью лететь в разных средах, материал, цвет и прочее). Для примера реализован только один - первоначальное направление броска. То есть запустили его и забыли. Как они там куда повтыкались и куда улетели нас не волнует. Главное - подчистить память за ними при выходе из функции (к примеру, при переходе на новую локацию).

В голову пришло использовать автоматический вызов деструктора по выходу из области видимости: создается один экземпляр класса на стеке - надзиратель - и как-то помечается. Остальные рабочие классы-томагавки создаются в куче (собственно по этому и надо за ними следить). Надзирателю доступны методы работы со всеми экземплярами, а рабочим только с самими собой. (Надзирателей может быть несколько)

Вооот. Реализация класса следующая (все вроде постарался расписать в комментариях):

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
class Tomagavk
{
 
public:
        Tomagavk():isOverseer( false )
                  {
                     countTomagavkLink.push_back( this );
                   };
        Tomagavk( bool isOverseer_ ):isOverseer( isOverseer_ )
                  {
                     // Здесь можно вставить проверку на создание только одного надзирателя. Если нужно
                     countTomagavkLink.push_back( this );
                   };
        ~Tomagavk(){
                    countTomagavkLink.erase(
                                      find( countTomagavkLink.begin(), countTomagavkLink.end(), this )
                                            );
 
                    if( this->isOverseer )     //// Автоматическая чистка при уничтожени надзирателя
                      {                        ////  При нескольких надзирателях тоже сработает
                      TerminateAllTomagavk();
                      cout << "Overseer is dead" << endl;
                      cin.ignore();
                      }
                    };
 
 
private:
        const bool isOverseer;
        static vector<Tomagavk *> countTomagavkLink; // Собственно сама считалка ////////////////
//------                                           ----------------------------------------------
private:                                           //// Какие-то полезные члены
        int way;                                     //
public:                                              //
        const int GetWay(){ return way; }            //
        void SetWay( int way_ ){ way = way_; }     ////
//------                                           ----------------------------------------------
public:                                            //// Общие методы. Для всех экземпляров
        void ShowItems(){
                        if( this->isOverseer )
                          for( vector<Tomagavk *>::iterator it = countTomagavkLink.begin();
                               it!=countTomagavkLink.end();
                               ++it )
                               {
                               cout << (*it)->GetWay() << endl;
                               }
                        cout << endl;
                        }
        bool TerminateAllTomagavk()
                        {
                        if( this->isOverseer )
                          for( vector<Tomagavk *>::iterator it = countTomagavkLink.begin();
                               it!=countTomagavkLink.end();
                               ++it )
                               {
                               if( !(*it)->isOverseer ) // Надзирателей не удаляем
                                 {
                                 (*it)->~Tomagavk(); // delete *it;
                                 --it;
                                 }
                               }
                        else
                          return false;
 
                        return true;
                        }
 
        //friend int main(); // Без этого никто не получит доступа к статичному полю
};
//---------------------------------------------------------------------------
vector<Tomagavk *> Tomagavk::countTomagavkLink; // Считалка обязательно должена быть объявлена //
                                                //  глобальной, чтобы не затиралась каждый раз
                                                //  при создании нового экземпляра класса
//---------------------------------------------------------------------------
 
int main()
{
Tomagavk overseer( true ); // Надзиратель томагавочный
                           // Только ему разрешено пользоваться общими функциями
                           //  так как он создан на стеке
                           // Контроль на программисте
 
 
Tomagavk *tom1 = new Tomagavk();    tom1->SetWay(11);     //// Создали
Tomagavk *tom2 = new Tomagavk();    tom2->SetWay(22);       //
Tomagavk *tom3 = new Tomagavk();    tom3->SetWay(33);     ////
 
overseer.ShowItems(); // Можно поглядеть, что на данный момент создано
 
//delete tom3;                                            //// Удалили какие-то
delete tom2;                                                //
//delete tom1;                                            ////
 
overseer.ShowItems(); // Можно поглядеть, что осталось
 
//tom2->ShowItems(); // А вот здесь косяк - после удаления экземпляра,
                     //  закрытый метод для него становится доступным
                     // Это связано со свойством isOverseer
                     // при удалении экземпляра оно становится равным true
                     // Если его инвертировать, то все в порядке
 
 
overseer.TerminateAllTomagavk();                        //// Подчистили
 
overseer.ShowItems(); // Проверили
 
//cout << Tomogavk::countTomagavkLink.size() << endl; // Если б main была friend, то сработало бы
 
cin.ignore();
return 0;
} // Надзиратель уничтожился (так же вызовется overseer.TerminateAllTomogavk() для всех неподчищеных хвостов)
  // В памяти остался только пустой вектор,
  //  который и будет задействован в случае создании еще экземпляров


Итак. Возникли следующие вопросы:
1) Что это за хрень? Х) Что-то среднее между сборщиком мусора и умным указателем?
2) Как вообще сама идея использовать подобным образом автоматический вызов деструктора для объекта, созданного на стеке, чтобы управлять созданными динамически?
3) Куда это можно применить?
4) Можно ли как-то узнать где именно создан конкретный объект - на стеке или в куче?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.03.2014, 11:29     Надзиратель томагавков или что за велосипед я изобрел?
Посмотрите здесь:

Ошибка или что-то.. C++
Что выбрать C++ или C#? C++
C++ Создать классы: колесо, велосипед и автомобиль (иерархия или композиция)
C++ Что лучше С++ 6 или С++ 2010 Что выбрать, мое мнение
посоветуйте какую-то книгу или даже видео курс,ну или еще что-то, ну чтобы с самого начала ,с нуля объяснялось. C++
Что быстрее assembler или c++ C++
C++ Что быстрее: i++ или ++i ?
Не получается "велосипед" на тему размерных величин C++
C++ Что лучше: динамические массивы, векторы, списки, map контейнеры или что-то ещё?
Что лучше c++ или c#? C++
C++ Пишу велосипед (shared_ptr)
Велосипед вместо std::atomic на WinApi C++ WinAPI

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
programina
03.03.2014, 14:32
  #2

Не по теме:

Что это за хрень?
Когда вижу string'и, vector'ы и прочие STL-штучки внутри классов, тоже возникает мысль: что это за хрень.

DrOffset
6840 / 4051 / 924
Регистрация: 30.01.2014
Сообщений: 6,855
03.03.2014, 21:34     Надзиратель томагавков или что за велосипед я изобрел? #3
Цитата Сообщение от SatanaXIII Посмотреть сообщение
1) Что это за хрень? Х) Что-то среднее между сборщиком мусора и умным указателем?
Да, похоже и на то и на другое. А еще - это синглтон и наполовину пул объектов.
Цитата Сообщение от SatanaXIII Посмотреть сообщение
2) Как вообще сама идея использовать подобным образом автоматический вызов деструктора для объекта, созданного на стеке, чтобы управлять созданными динамически?
Этой идее "сто лет" и реализуется она с помощью RAII. Это либо пул объектов, либо контейнер умных указателей.

Цитата Сообщение от SatanaXIII Посмотреть сообщение
3) Куда это можно применить?
В таком виде - никуда. Главное достоинство в виде статического вектора регистрируемых элементов, одновременно является главным недостатком (т.к. сложно контролировать консистентность такого вектора (особенно в условиях многопоточности)).
Чтобы его попробовать реально применять нужно объектам сделать счетчик ссылок, иначе удаление извне сделает ранее полученные ссылки невалидными. И запретить использование голых указателей, по той же причине. Так же присутствует определенное ограничение на многопоточное применение (возможно помог бы thread-local, но это уже зависит от задачи).

Вообще такое совмещение функциональности видится мне антипаттерном, т.к. одна и та же сущность имеет кардинально разные условия применимости.
Цитата Сообщение от SatanaXIII Посмотреть сообщение
4) Можно ли как-то узнать где именно создан конкретный объект - на стеке или в куче?
Переносимого способа нет, как нет и гарантированно рабочего в большинстве ситуаций непереносимого.

Можно попробовать сделать одну из двух вещей:
1) Запретить создание объектов на стеке (конструкторы в приват, делаем статическую функцию Create, которая создает объект требуемым способом).
2) Запретить создание объектов в куче, поместив оператор new в приват. Однако этот запрет обходится при желании.
В любом случае это потребует разнесения в разные классы (объекты одного живут только на стеке, другого - только в куче).

Ну и вот в коде углядел вот это:
C++
1
2
3
4
5
6
7
8
9
10
11
//delete tom3;                                            //// Удалили какие-то
delete tom2;                                                //
//delete tom1;                                            ////
 
overseer.ShowItems(); // Можно поглядеть, что осталось
 
//tom2->ShowItems(); // А вот здесь косяк - после удаления экземпляра,
                     //  закрытый метод для него становится доступным
                     // Это связано со свойством isOverseer
                     // при удалении экземпляра оно становится равным true
                     // Если его инвертировать, то все в порядке
Но ведь обращение по указателю, к которому был применен delete - это UB, о каком доступе вообще может идти речь?
Yandex
Объявления
03.03.2014, 21:34     Надзиратель томагавков или что за велосипед я изобрел?
Ответ Создать тему
Опции темы

Текущее время: 11:31. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru