Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
1

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

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

Author24 — интернет-сервис помощи студентам
Название: She2.jpg
Просмотров: 90

Размер: 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) Можно ли как-то узнать где именно создан конкретный объект - на стеке или в куче?
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.03.2014, 11:29
Ответы с готовыми решениями:

Мой Paint или изобретаем велосипед
Здравствуйте! Я пришёл сюда из другого довольно известного форума, активность на котором, к...

Файловая система. Велосипед или существующая
Я посмотрел файловые системы FAT, и подумал что там есть ограничения которые в некоторых случаях...

StmGL :) Или хотим изобрести велосипед
Всем привет! Имеем STM32F7 с интерфейсом LTDC. Все работает очень шикарно с базовой поддержкой...

Велосипед из костылей или две формы на одну таблицу
Всем категорическое здравствуйте! Знаю, что злоупотребляю вниманием уважаемой аудитории, но есть...

2
programina
03.03.2014, 14:32
  #2

Не по теме:

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

0
18840 / 9839 / 2408
Регистрация: 30.01.2014
Сообщений: 17,280
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, о каком доступе вообще может идти речь?
1
03.03.2014, 21:34
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.03.2014, 21:34
Помогаю со студенческими работами здесь

Создать классы: колесо, велосипед и автомобиль (иерархия или композиция)
Помогите решить задачу очень нужно: Создать классы: колесо, велосипед и автомобиль. ...

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

Шахматы Next - изобрел россянин
Покажите новые доски простместерам,что они скажут про новые типы досок Это изобретение...


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

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru