jeudi 22 septembre 2016

Two step constructions for enable_shared_from_this object that needs to pass std::shared_ptr

I know that additional initialization methods are evil, as they leave a very nasty option for having object half-constructed and as result all methods needs to check for this. But what about this situation?

class config;
class cfg_item final
{
    private:
        friend class config;
        cfg_item(std::weak_ptr<config> owner) : owner(owner) { }
        std::weak_ptr<config> owner;
}
class config final : private std::enable_shared_from_this<config>
{
    public:
        config()
        {
             items.emplace(std::make_shared<cfg_item>(weak_from_this())); // Will crash!
        }
    private:
        std::vector<std::shared_ptr<cfg_item>> items;
}
int main(int argc, char * argv[])
{
    std::shared_ptr<config> cfg = std::make_shared<config>();
}

I KNOW WHY IT CRASHES. The std::shared_ptr in the main is not yet initialized with shared pointer to config instance, so constructor does not know how to make weak_from_this and just raises std::bad_weak_ptr exception because there are no valid std::shared_ptr pointing to this at constructor's call time.

The question is: how can I avoided the whole thing? I believe the only way I see would be to add separate initialization method, which is evil as I've already mentioned...

As note about real code: the constructors loads cfg_item from external source. It is assumed that all cfg_items are available for the entire lifetime of config. The weak pointers back to config are mandatory, as cfg_item must push all changes done to it back to config to save to external source

Aucun commentaire:

Enregistrer un commentaire