мой факап с умными указателями
От: Кодт Россия  
Дата: 02.12.23 01:15
Оценка: 7 (2) +1
Представим себе вот такой дистиллированный говнокод
struct IFace { ..... };

class TheImpl : public IFace { ..... };

class TheFixture {
public:
    IFace& iface() { return aggregate_; }
private:
    TheImpl aggregate_;
    // и ещё всякий клей, вспомогательные объекты, связи и функции
};

class TheProvider {
public:
    std::shared_ptr<IFace> provide() {
        if (need_create())
            create_cached_object();
        return cached_object_;
    }

private:
    std::shared_ptr<IFace> cached_object_;

    bool need_create() {
        return !cached_object_ || ....;  // кеша нет, кеш протух, всё такое...
    }

    // вот тут живёт бажок!
    void create_cached_object() {
        auto cached_object = std::make_shared<TheFixture>();
        cached_object_ = std::shared_ptr<IFace>{cached_object_, &cached_object->iface()};
    }
};


shared_ptr позволяет владеть объектом-сборкой, отдавая интерфейс на агрегат.
Например, указатель на узел дерева или даже на содержимое узла дерева.

https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr — сигнатура номер 8, "aliasing constructor"

Это даёт возможности очень гибко создавать всякие нетривиальные реализации интерфейсов.

Проблема в том, что нет никакого контроля — ни типа, ни значения аргументов такого конструктора.
Можно делать вот такие странные указатели: https://gcc.godbolt.org/z/ncz88ovW4

Тем не менее, заниматься самоприсваиванием с изменением указателя на агрегат — вполне легально и даже может иметь практический смысл:
https://gcc.godbolt.org/z/edEzMe953

Но с такой же лёгкостью мы можем получить преждевременный конец времени жизни!
Что я и получил, сделав опечатку в реальном проекте!

Здесь привожу иллюстрацию без NDA-подробностей.

Дистиллированный код — с багом и с исправлением:
https://gcc.godbolt.org/z/x53daYc5P
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.