Juliean

GDNet+ Basic
  • Content count

    1581
  • Joined

  • Last visited

Community Reputation

7062 Excellent

About Juliean

Personal Information

  1. You mean something like this? class Signal { ~Signal(void) { m_isDead = true; } void Emit(void) const { for(auto& delegate : m_list) { delegate(); if(m_isDead) break; } } private: bool m_isDead; } Seems a bit hacky & unsafe though - I imagine you had something different in mind, but since signals are just standalone classes that are composed into other classes, there's currently no other (easy) way to let the loop know. I'm also not sure if thats even a good idea. Its usually important that all slots are correctly notified, even if one of them ends up terminating the signal - otherwise it can lead to invalid state/further crashes. Especially since the order of the slots is not guaranteed, this can easily lead to undefined behaviour, based on which slot is called first on any given time. I quess in that sense, creating a copy of the list is a necessary "evil".
  2. Come to think of it, I'm already doing what you describe for my entities/game objects, at least. Having a game-object destroyed while its script is running/issuing the destroy command was something I encountered quite early, and alleviated by introducing a destroyed-queue like you described. For widgets (which is my primary source of pain regarding this topic), I never though of doing that. There's a certain additional level of complication that I didn't make clear yet, though: - Widgets are generally user-managed. Meaning, they are mostly created & stored by a std::unique_ptr in the user code. I used some managed storage before, and it caused different problems, so I ended up this way. On the other hand, this means that its neigh impossible to introduce a dead-widget queue to solve the problem. For example, pseudo-code for a asset-viewer that allows to tab between different assets: class AssetView { using TabMap = std::unordered_map<Asset*, std::unique_ptr<AssetTabView>>; private: void OnCloseTab(Asset* pAsset) // isued by TabBar::TabItem::SigClose { m_pTabs->RemoveTab(pAsset); // oups m_mTabs.erase(pAsset); } std::unique_ptr<TabBar> m_pTabs; TabMap m_mTabs; } This at the very least means that TabBar has to implement its own dead-widget queue, or I have to implement the delayed-destroy in the user code, like in this "AssetView". - This, unlike the example with the game-objects, can also happen when a slot gets removed from/added to the signal while iterating, as this will also invalidate iterators. This happens more often then you'd probably imagine - ie. when reloading the generated shader code of my "material"-system, this sometimes forces new material-instances to be generated, which in turn will have to register with the "SigReload" of its material-class. Now sure, another thing where I could just delay the initialization, but quite frankly, this happens so frequently that it becomes a huge pain in the ass, having to delay everything without much added benefit (IMHO; as opposed to game-objects where it makes quite much sense).
  3. So I've been using this signal/slot-library for quite some time now: https://github.com/pbhogan/Signals One rather "common" pattern I encountered, is a signal that destroys its owning class: class Widget { core::Signal<> SigClicked; } void onCloseWindow(void) { delete &widget; } widget.SigClicked.Connect(&onCloseWindow); widget.SigClicked(); // ... Now this is going a bit into the details of how signals is implemented - internally it stores an std::set, which in the operator() is iterated via a for-loop: void Signal::operator()() const { for(auto& delegate : delegate_list) { delegate.Call(); } } Now can you imagine what happens when any of the delegates destroys the object that owns the Signal? Obviously this will result in the destructor of the Signal being called, after which it will resume to iterate over the list - crash, in the best case I've encountered multiple strategies to combat this - the most obvious that I know is to simply delay the delete/destroy-operator, ie. by performing it in the next tick-step. This can overcomplicate things though, so I searched for a simpler solution-until I finally found one: void Signal::EmitSafe() const { const auto temp_list = delegate_list; for(auto& delegate : temp_list) { delegate.Call(); } } Now I'm not sure if thats a coding-horror, or an actual elegant solution for this problem Its not universal though, since due to the overhead of copying the list everytime, I only use it where I can expect something like this to happen. Did you ever have fun with objects trying to delete themselves in a similar fasion? I'd also like to hear some suggestions of what you'd do to solve that
  4. Thanks, I submitted a ticket to the support portal. Not sure its related to the site upgrade, though unless I'm mistaken (that just happened yesterday, didn't it?) - as I mentioned the failed payment happened a few weeks ago, I just looked at my bills today and noticed that the payment was successfull with the new card
  5. Hi, so there was a problem with my subscription to GDNet+. Basically my credit card expired at the time it tried to resubscribe, so I updated it, after which I got told its going to try again on some later date. Now I just saw that the subscription fee has been paid from my account, yet I'm still not showing as GDNet+-member. Well, I hope this is the right place to report this issue, and hope it can be resolved. Its actually been some time since this happened, but I only saw the money has been booked right now. Thanks!