Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++

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

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

03.03.2014, 11:29. Просмотров 540. Ответов 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) Можно ли как-то узнать где именно создан конкретный объект - на стеке или в куче?
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.03.2014, 11:29
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Надзиратель томагавков или что за велосипед я изобрел? (C++):

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

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

Профессор Москалев изобрел водку в таблетках - Другие науки
Евгений Москалев, профессор Санкт-Петербургского Технологического Университета изобрел сухую водку. Алкопорошок можно принимать в виде...

подскажите по сложным производным, а то я кажется вечный двигатель изобрел уже - Математический анализ
Есть функция h(a,b,c), в свою очердеь a(t), b(t), c(t)...Тогда частная производную от h можем раскрыть по формуле производной сложной...

Как или что написать или дописать что бы программа заработала. - C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { ...

Злой гений изобрел луч смерти и навел его на планету, находясь при этом на спутнике - Pascal ABC
Входной файл: z.in Выходной файл: z.out Злой гений изобрел луч смерти и навел его на планету, находясь при этом на спутнике. В...

2
programina
03.03.2014, 14:32
  #2

Не по теме:

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

0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
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
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.03.2014, 21:34
Привет! Вот еще темы с ответами:

Велосипед - Pascal
составит программу, рисующая велосипед

.NET 3.x Или PageMethods или AJAX или еще что? - C# ASP.NET
У меня есть на странице FileUpoader и кнопочка &quot;Обновить аватарку&quot;. То есть я клацаю на Обзор... выбираю файл и потом нажимаю на кнопочку,...

Велосипед .children .parent - jQuery
Всем привет! Можно ли переписать данный код более компактно? $(document).ready(function(){ ...

Зачем изобретать велосипед? - Pure Basic
Здравствуйте, подскажите пожалуйста, как написать код, который бы открывал программу (что-то типа калькулятора), вводил нужные нам данные в...


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

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Опции темы

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