Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.134.78.106] |
|
Страницы: (3) 1 [2] 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Цитата Wound @ В смысле поэкспериментировать? Дело в том, что когда ты пишешь = delete, то компилятор выбрасывает этот член класса. И если вдруг ты его юзнул - тебе он так и скажет, такоой метод помечен как удаленный, так что вызывай другой. А когда ты его делаешь закрытым, то вполне можешь выхватить ошибку аля: не могу вызвать такой метод, он находится в секции private. Когда речь идет о небольшой логике - никаких проблем не будет. Но вдруг если будет что то понавороченее, например с какими нибудь итераторами внутри second/first или еще чего, которые нужно будет куда нибудь перенести или скопировать, то можешь потратить много времени, на выявление ошибок. Проверил сообщения. Для public секции: prog.cpp: In function ‘int main()’: prog.cpp:10:5: error: use of deleted function ‘A::A()’ A a; ^ prog.cpp:6:5: note: declared here A() = delete; ^ Для private секции: prog.cpp: In function ‘int main()’: prog.cpp:10:5: error: ‘A::A()’ is private within this context A a; ^ prog.cpp:6:5: note: declared private here A() = delete; ^ Может ты и прав. Но пока я существенного не замечаю. Может потом... Добавлено Класс Holder обеспечивает автоматическую инициализацию после создания экземпляра класса, и автоматическую очистку перед разрушением экземпляра класса. Это некое подобие функционала из Дэлфи (линк). |
Сообщ.
#17
,
|
|
|
Ну вот так наверное как то:
template<typename T> struct Singleton { private: Singleton() = default; ~Singleton() = default; public: Singleton(const Singleton&) = delete; Singleton& operator= (const Singleton&) = delete; Singleton(Singleton&&) = delete; Singleton& operator= (Singleton&&) = delete; static Singleton& Instance() { static Singleton<T> instance; return instance; } T Value() const { return Singleton<T>::Instance().m_value; } T& Value() { return Singleton<T>::Instance().m_value; } private: T m_value; }; class A { public: void print() { std::cout << "A" << std::endl; } }; class B { public: void print() { std::cout << "B" << std::endl; } }; int main() { Singleton<A>& instA = Singleton<A>::Instance(); Singleton<B>& instB = Singleton<B>::Instance(); instA.Value().print(); instB.Value().print(); std::cin.get(); return 0; } Это если конкретно через синглтон. Добавлено Цитата JoeUser @ Может ты и прав. Но пока я существенного не замечаю. Может потом... Ну ты на всех компиляторах проверил? А то например в 2017 студии пишет: 1>e:\develop\main.cpp(178): error C2248: 'C::C': cannot access private member declared in class 'C' 1>e:\develop\main.cpp(172): note: see declaration of 'C::C' 1>e:\develop\main.cpp(169): note: see declaration of 'C' Вот для вызова конструктора для такого класса: class C { private: C() = delete; }; В других компиляторах может быть иначе. Но я не вижу вообще никакого здавого смысла делать приватными удаляемые члены. Профита вообще 0. А вот если привыкнуть делать их открытыми, то профита куда больше. Цитата JoeUser @ Класс Holder обеспечивает автоматическую инициализацию после создания экземпляра класса, и автоматическую очистку перед разрушением экземпляра класса. Это некое подобие функционала из Дэлфи (линк). Ничего он там не обеспечивает. Он накладывает ограничения на используемый класс. Вообще в С++ все эти действия делаеются в конструкторе/деструкторе. А для умных указателей shared_/unique/weak можно передать функцию deleter, если тебе нужно как то по особому очистить ресурс. |
Сообщ.
#18
,
|
|
|
Цитата Wound @ Это если конкретно через синглтон. Вариант рабочий, но ИМХО, по ТЗ - не то. Топикстартеру нужно все глобальные переменные инкапсулировать в один класс, и потом дать к ним доступ из других классов. По твоему примеру это - в классах A и В должен быть доступ к таким переменным. А там пока только печать константной строки. |
Сообщ.
#19
,
|
|
|
Цитата Wound @ Ничего он там не обеспечивает. Ну не тупи Holder() { std::cout << "Holder()::Holder()" << std::endl; if (!Self) Self = new T(); Self->Init(); // <----------------------------------------- инициализация ПОСЛЕ создания а не ВО ВРЕМЯ } ~Holder() { if (Self) { Self->Cleanup(); // < ----------------------------------- очистка ДО начала процесса разрушения delete Self; std::cout << "~Holder()::Holder()" << std::endl; } } Умным указателям, как я понял, можно передать ТОЛЬКО "удалитель". Добавлено Киля, чтобы было понятно - напомню откуда "ноги растут" в моем коде. В С++ в конструкторе нельзя вызывать виртуальные функции. Таким образом только деструктор может быть виртуальным. Мой код обеспечивает функционал "виртуального конструктора". Как-то так. Добавлено Цитата Wound @ Ну ты на всех компиляторах проверил? А то например в 2017 студии пишет: Если честно, я еще ни одной программы не скомпилировал в студии. Потому, что ее у меня нет. Хватает GCC и clang. Кстати, вот что пишет clang для ПРИВАТНОЙ секции: prog.cc:10:5: error: call to deleted constructor of 'A' A a; ^ prog.cc:6:5: note: 'A' has been explicitly marked deleted here A() = delete; ^ 1 error generated. Выкинь студию! |
Сообщ.
#20
,
|
|
|
Цитата JoeUser @ Ну не тупи Попробуй передать в свой Holder класс у которого нет Init и Cleanup, и ты поймешь о чем я. Цитата JoeUser @ Топикстартеру нужно все глобальные переменные инкапсулировать в один класс, и потом дать к ним доступ из других классов. И в чем проблема? Получай на здоровье, например так: template<typename T> struct Singleton { private: Singleton() = default; ~Singleton() = default; public: Singleton(const Singleton&) = delete; Singleton& operator= (const Singleton&) = delete; Singleton(Singleton&&) = delete; Singleton& operator= (Singleton&&) = delete; static Singleton& Instance() { static Singleton<T> instance; return instance; } T Value() const { return Singleton<T>::Instance().m_value; } T& Value() { return Singleton<T>::Instance().m_value; } private: T m_value; }; class A { public: void print() { std::cout << "A: " << a << std::endl; } int a; }; class B { public: void print() { std::cout << "B: " << b << std::endl; } int b; }; class C { public: void DoSomething() { Singleton<A>& instA = Singleton<A>::Instance(); Singleton<B>& instB = Singleton<B>::Instance(); instA.Value().print(); instB.Value().print(); } }; int main() { Singleton<A>& instA = Singleton<A>::Instance(); Singleton<B>& instB = Singleton<B>::Instance(); instA.Value().a = 10; instB.Value().b = 20; instA.Value().print(); instB.Value().print(); std::cout << "-------C---------" << std::endl; C c; c.DoSomething(); std::cin.get(); return 0; } Это же синглентон, где хочешь там и вызывай его. У тебя гарантированно будет 1 экземпляр класса. |
Сообщ.
#21
,
|
|
|
Цитата Wound @ Попробуй передать в свой Holder класс у которого нет Init и Cleanup, и ты поймешь о чем я. Так это же специально и сделано было для этого! |
Сообщ.
#22
,
|
|
|
Цитата JoeUser @ Умным указателям, как я понял, можно передать ТОЛЬКО "удалитель". Cоздатель, ВНЕЗАПНО, вызывается в момент конструирования указателя. Что целиком и полностью удовлетворяет идиоме RAII. Цитата JoeUser @ Киля, чтобы было понятно - напомню откуда "ноги растут" в моем коде. В С++ в конструкторе нельзя вызывать виртуальные функции. Таким образом только деструктор может быть виртуальным. Мой код обеспечивает функционал "виртуального конструктора". Как-то так. Твой код накладывает ограничение на использование объектов разных типов. Что если мне нужно передать в твой Holder shared_ptr объект? Цитата JoeUser @ Если честно, я еще ни одной программы не скомпилировал в студии. Потому, что ее у меня нет. Хватает GCC и clang. Кстати, вот что пишет clang для ПРИВАТНОЙ секции: Речь идет не о конкретно студии. Речь идет о хорошем стиле программирования. Писать удаленные методы в приватной секции не по феншую. Понимаешь? Добавлено Цитата JoeUser @ Так это же специально и сделано было для этого! Зачем? Что бы постоянно городить обертки с пустыми Init и Cleanup? |
Сообщ.
#23
,
|
|
|
Цитата Wound @ И в чем проблема? Проблема в том, что эти переменные "а" и "b" должны хранится вне классов A и B. Ну прочти самое первое сообщение топикстартера |
Сообщ.
#24
,
|
|
|
Цитата JoeUser @ Проблема в том, что эти переменные "а" и "b" должны хранится вне классов A и B. Если ты еще не понял, то эти классы A и B и есть переменные, которые должны храниться вне этих классов. Попробуй выкинуть классы A и B. Если тебе нужны примитивные типы, создай структуру с нужным количеством членов и передай в синглтон. Все. |
Сообщ.
#25
,
|
|
|
Цитата Wound @ Попробуй передать в свой Holder класс у которого нет Init и Cleanup, и ты поймешь о чем я. Тут ничего страшного. В принципе можно еще шаблонами поиграться, чтобы на этапе компиляции вырезать вызовы. Лениво. Я уповаю на оптимизатор - их и так там не будет. Цитата Wound @ Если ты еще не понял, то эти классы A и B и есть переменные, которые должны храниться вне этих классов. Попробуй выкинуть классы A и B. Если тебе нужны примитивные типы, создай структуру с нужным количеством типов и передай в синглтон. Все. Просто сделай как просит топикстартер Добавлено Цитата Wound @ Cоздатель, ВНЕЗАПНО, вызывается в момент конструирования указателя. Это не гибко. Я уже писал выше о невозможности сделать штатными средствами виртуальное конструирование. |
Сообщ.
#26
,
|
|
|
Цитата JoeUser @ Тут ничего страшного. В принципе можно еще шаблонами поиграться, чтобы на этапе компиляции вырезать вызовы. Лениво. Я уповаю на оптимизатор - их и так там не будет. А то, что тебе каждый раз придется делать обертки над типами, у которых нет этих методов - тебя не смущает? Цитата JoeUser @ Просто сделай как просит топикстартер Он просит чтоб было вот так, как я понял? Цитата mishapk @ Пример. До: int a,b,c,d; - глобальные переменные class Tx; - использует глобальные переменные class Ty; - использует глобальные переменные После: Myclass { private: int a,b,c,d; public: Tx x; Ty y; } Какие будут идеи? В такой постановке задачи, я сделаю соответствующие конструкторы у классов Tx/Ty И передам нужные переменные из класса MyClass Добавлено Цитата JoeUser @ Это не гибко. Я уже писал выше о невозможности сделать штатными средствами виртуальное конструирование. Че это не гибко? А вызывать Init и Cleanup гибко? Конструктор/Деструктор вроде как раз их и заменяют, не? |
Сообщ.
#27
,
|
|
|
Цитата Wound @ В такой постановке задачи, я сделаю соответствующие конструкторы у классов Tx/Ty И передам нужные переменные из класса MyClass По секрету: там будет 128 переменных! Цитата Wound @ А то, что тебе каждый раз придется делать обертки над типами, у которых нет этих методов - тебя не смущает? Можно предусмотреть базовый класс с пустыми вызовами, а в наследниках про эти функции забыть. Элементарно, Ватсон! Цитата Wound @ Конструктор/Деструктор вроде как раз их и заменяют, не? Напоминаю! В конструкторе нельзя вызывать виртуальные функции. В моем коде - это решается. |
Сообщ.
#28
,
|
|
|
Цитата JoeUser @ По секрету: там будет 128 переменных! Тогда я объявлю массив и передам массив. Если у меня куча классов, где эти переменные нужны, создам структуру, как я тебе писал выше и передам ее в синглтон. Структуру написать? Ок struct MyType { int variable1; shared_ptr<int> variable2; MyObject variable3; std::vector<some type> variable4; ololo variable5; int variable6; int variable7; ... }; .. auto& gVar = Singlenton<MyType>::Instance(); gVar.Value().bla bla bla Цитата JoeUser @ Можно предусмотреть базовый класс с пустыми вызовами, а в наследниках про эти функции забыть. Элементарно, Ватсон! Ну вот я захотел передать в твой холдер std::shared_ptr<A> че мне делать то? Цитата JoeUser @ Напоминаю! В конструкторе нельзя вызывать виртуальные функции. В моем коде - это решается. А зачем это нужно то? Я что сам не могу вызвать Init/Cleanup, если мне понадобиться? А что если у меня Cleanup может генерировать исключение? Выходят я получу граблями в лоб из за твоего мега кода? |
Сообщ.
#29
,
|
|
|
Цитата Wound @ Тогда я объявлю массив и передам массив. Блин Ну так твой MyType и есть мой Global !!! Цитата Wound @ Ну вот я захотел передать в твой холдер std::shared_ptr<A> че мне делать то? Не пробовал, не знаю. Заверни его в структуру или класс и передай. Надо пробовать. Цитата Wound @ А зачем это нужно то? Я что сам не могу вызвать Init/Cleanup, если мне понадобиться? А можешь и забыть. А ненаследованный класс тебя заставит не забыть. Цитата Wound @ Подавляй. Считай - это полноценная часть деструктора. В деструкторе же ты не собираешься бросать исключения? Или собираешься? А что если у меня Cleanup может генерировать исключение? Выходят я получу граблями в лоб из за твоего мега кода? |
Сообщ.
#30
,
|
|
|
Цитата JoeUser @ Блин Ну так твой MyType и есть мой Global !!! Нет, у меня MyType - это структура это отдельный тип, который агрегирует в себе 7 переменных разных типов, и передается в синглентон. У тебя твой Holder может принять ровно 1 объект одного типа, и зачем то вызывает для него Init в конструкторе и Cleanup в деструкторе. Моя структура чем то отдаленно похожа на твой класс Global, и то я не уверен в этом. Цитата JoeUser @ Не пробовал, не знаю. Заверни его в структуру или класс и передай. Надо пробовать. Так я тебе скажу - оно не скомпилируется. А потом, если допустим даже предположить, что я завернул свой shared_ptr в класс и определил там методы Init и Cleanup - то даже в этом случае твой код небезопасен в плане исключений, потому как не дай бог у меня внутри функции Init что то понасоздается, а потом вдруг произойдет исключение в ней же. Все, каюк утечка ресурсов обеспечена. Цитата JoeUser @ А можешь и забыть. А ненаследованный класс тебя заставит не забыть. Я так не пишу, соответственно и забывать мне нечего. Твой код не удовлетворяет RAII, соответственно он не безопасный. Цитата JoeUser @ Подавляй. Считай - это полноценная часть деструктора. В деструкторе же ты не собираешься бросать исключения? Или собираешься? Дело в том, что деструктор - это часть языковой конструкции класса, поведение которой четко оговорено, и я знаю что от него ожидать или нет. А твой метод Cleanup - ни к селу ни к городу. Добавлено Во, попробовал поиграться с твоим кодом, выхватил по щам в рантайме: https://ideone.com/VP5Y8i #include <iostream> #include <memory> template<typename T> struct Holder { Holder() { std::cout << "Holder()::Holder()" << std::endl; if (!Self) Self = new T(); Self->Init(); } ~Holder() { if (Self) { Self->Cleanup(); delete Self; std::cout << "~Holder()::Holder()" << std::endl; } } T* Self = nullptr; }; class SomeClass { public: void Init(){} void Cleanup() {} int member; }; //////////////////////////////////////////////////////////////////////////////////////// template <typename T> class Singleton { public: static T* Instance() { std::cout << "Singlton::Instance()" << std::endl; static Holder<T> Dummy; return Dummy.Self; } private: Singleton() = delete; Singleton(Singleton const&) = delete; Singleton& operator= (Singleton const&) = delete; Singleton(Singleton const&&) = delete; Singleton& operator= (Singleton const&&) = delete; }; int main() { { auto pInst = Singleton<SomeClass>::Instance(); pInst->member = 10; std::cout << pInst->member << std::endl; std::unique_ptr<SomeClass> pObj(pInst); } auto pInst = Singleton<SomeClass>::Instance(); pInst->member = 20; return 0; } *** Error in `./prog': double free or corruption (fasttop): 0x0000557abbacbc30 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x70bcb)[0x2ba3cbcb8bcb] /lib/x86_64-linux-gnu/libc.so.6(+0x76f96)[0x2ba3cbcbef96] /lib/x86_64-linux-gnu/libc.so.6(+0x7778e)[0x2ba3cbcbf78e] ./prog(+0xe77)[0x557ab9b48e77] /lib/x86_64-linux-gnu/libc.so.6(+0x35920)[0x2ba3cbc7d920] /lib/x86_64-linux-gnu/libc.so.6(+0x3597a)[0x2ba3cbc7d97a] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf8)[0x2ba3cbc682b8] ./prog(+0xd4a)[0x557ab9b48d4a] ======= Memory map: ======== 2ba3caf68000-2ba3caf8b000 r-xp 00000000 fd:00 2840974 /lib/x86_64-linux-gnu/ld-2.24.so 2ba3caf8b000-2ba3caf8f000 rw-p 00000000 00:00 0 2ba3caf98000-2ba3caf9d000 rw-p 00000000 00:00 0 2ba3cb18b000-2ba3cb18c000 r--p 00023000 fd:00 2840974 /lib/x86_64-linux-gnu/ld-2.24.so 2ba3cb18c000-2ba3cb18d000 rw-p 00024000 fd:00 2840974 /lib/x86_64-linux-gnu/ld-2.24.so 2ba3cb18d000-2ba3cb18e000 rw-p 00000000 00:00 0 2ba3cb18e000-2ba3cb300000 r-xp 00000000 fd:00 2967755 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22 2ba3cb300000-2ba3cb500000 ---p 00172000 fd:00 2967755 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22 2ba3cb500000-2ba3cb50a000 r--p 00172000 fd:00 2967755 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22 2ba3cb50a000-2ba3cb50c000 rw-p 0017c000 fd:00 2967755 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22 2ba3cb50c000-2ba3cb510000 rw-p 00000000 00:00 0 2ba3cb510000-2ba3cb613000 r-xp 00000000 fd:00 2841003 /lib/x86_64-linux-gnu/libm-2.24.so 2ba3cb613000-2ba3cb812000 ---p 00103000 fd:00 2841003 /lib/x86_64-linux-gnu/libm-2.24.so 2ba3cb812000-2ba3cb813000 r--p 00102000 fd:00 2841003 /lib/x86_64-linux-gnu/libm-2.24.so 2ba3cb813000-2ba3cb814000 rw-p 00103000 fd:00 2841003 /lib/x86_64-linux-gnu/libm-2.24.so 2ba3cb814000-2ba3cb82a000 r-xp 00000000 fd:00 2840941 /lib/x86_64-linux-gnu/libgcc_s.so.1 2ba3cb82a000-2ba3cba29000 ---p 00016000 fd:00 2840941 /lib/x86_64-linux-gnu/libgcc_s.so.1 2ba3cba29000-2ba3cba2a000 r--p 00015000 fd:00 2840941 /lib/x86_64-linux-gnu/libgcc_s.so.1 2ba3cba2a000-2ba3cba2b000 rw-p 00016000 fd:00 2840941 /lib/x86_64-linux-gnu/libgcc_s.so.1 2ba3cba2b000-2ba3cba43000 r-xp 00000000 fd:00 2840960 /lib/x86_64-linux-gnu/libpthread-2.24.so 2ba3cba43000-2ba3cbc42000 ---p 00018000 fd:00 2840960 /lib/x86_64-linux-gnu/libpthread-2.24.so 2ba3cbc42000-2ba3cbc43000 r--p 00017000 fd:00 2840960 /lib/x86_64-linux-gnu/libpthread-2.24.so 2ba3cbc43000-2ba3cbc44000 rw-p 00018000 fd:00 2840960 /lib/x86_64-linux-gnu/libpthread-2.24.so 2ba3cbc44000-2ba3cbc48000 rw-p 00000000 00:00 0 2ba3cbc48000-2ba3cbddd000 r-xp 00000000 fd:00 2841097 /lib/x86_64-linux-gnu/libc-2.24.so 2ba3cbddd000-2ba3cbfdc000 ---p 00195000 fd:00 2841097 /lib/x86_64-linux-gnu/libc-2.24.so 2ba3cbfdc000-2ba3cbfe0000 r--p 00194000 fd:00 2841097 /lib/x86_64-linux-gnu/libc-2.24.so 2ba3cbfe0000-2ba3cbfe2000 rw-p 00198000 fd:00 2841097 /lib/x86_64-linux-gnu/libc-2.24.so 2ba3cbfe2000-2ba3cbfe6000 rw-p 00000000 00:00 0 2ba3cc000000-2ba3cc021000 rw-p 00000000 00:00 0 2ba3cc021000-2ba3d0000000 ---p 00000000 00:00 0 557ab9b48000-557ab9b4a000 r-xp 00000000 fd:00 23353346 /home/g1NiFf/prog 557ab9d49000-557ab9d4a000 r--p 00001000 fd:00 23353346 /home/g1NiFf/prog 557ab9d4a000-557ab9d4b000 rw-p 00002000 fd:00 23353346 /home/g1NiFf/prog 557abbab9000-557abbaeb000 rw-p 00000000 00:00 0 [heap] 7fff4aec3000-7fff4aee4000 rw-p 00000000 00:00 0 [stack] 7fff4afee000-7fff4aff0000 r-xp 00000000 00:00 0 [vdso] 7fff4aff0000-7fff4aff2000 r--p 00000000 00:00 0 [vvar] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Это я еще не генерировал исключение в Init. |