Можете ли вы использовать член delete для сохранения shared_ptr? - PullRequest
2 голосов
/ 16 мая 2019

Даны следующие типы

// interface and implementation used in one part of the codebase
struct Image
{
    virtual std::vector<uint8_t>& GetData () = 0;
};

struct VecImage : public Image
{
    std::vector<uint8_t> mData;

    std::vector<uint8_t>& GetData () { return mData; }
};

// used in another part of the codebase
struct PtrImage
{
    std::shared_ptr<uint8_t> mData;

    PtrImage (std::shared_ptr<Image> pIm);
};

следующий конструктор - вменяемый и правильный способ преобразования Image в PtrImage?

PtrImage::PtrImage (std::shared_ptr<Image> pIm)
{
    struct im_deleter
    {
        std::shared_ptr<Image> keepAlive;
        void operator () (uint8_t* ptr)
        {
            keepAlive.reset ();
        }
    };

    mData = { &pIm->GetData()[0], im_deleter { pIm } };
}

PtrImage используется как «тип значения», его передают по значению, а Image передают только в shared_ptrs.

Ответы [ 3 ]

3 голосов
/ 16 мая 2019

является следующим конструктором в здравом уме ..

Вы продлеваете время жизни Image благодаря деструктору, поэтому data остается в силе. Таким образом, вы правы в этом вопросе ...

Но , вектор может перераспределить, аннулируя буфер.

Поэтому полученный код небезопасен.

Вы можете хранить std::shared_ptr<std::vector<uint8_t>> mData; на всякий случай.

.. и правильный путь

У нас лучше / проще с псевдонимом конструктора из std::shared_ptr:

struct PtrImage
{
    std::shared_ptr<std::vector<uint8_t>> mData;

    PtrImage (std::shared_ptr<Image> pIm) : mData(pIm, &pIm->GetData()) {}
};

Таким образом, информация о владельце PtrImage::mData передается pIm.

Примечание: Я предполагаю, что вектор, возвращаемый GetData(), имеет то же (или большее) время жизни, что и Image (как для VecImage). если это не связанный вектор (от другого объекта), то у вас не будет решения.

Как отмечено в комментарии, вектор не должен перераспределять ни

1 голос
/ 16 мая 2019

Выглядит довольно опасно для меня:

std::shared_ptr<Image> i = std::make_shared<VecImage>(/* some data */);
PtrImage p(i); // has now stored a pointer to the vector's data
i->getData()->push_back(0); // repeat until re-allocation occurs!

Что бы теперь держал p ?Общий указатель содержит указатель на данные, которые находились в векторе до перераспределения;но эти данные были заменены и удалены.Итак, теперь у вас есть висячий указатель, хранящийся в p (в указателе uint8_t), его использование (что произойдет не позднее, когда ваш умный указатель попытается удалить свои данные) приведет к неопределенному поведению.

0 голосов
/ 16 мая 2019

Вы даже не должны пытаться иметь общий указатель, догадающийся, должен ли он удалить свой объект или нет.Если вы продолжите в том же духе, вы будете захвачены угловым делом или даже если вам удалось все найти, новым, созданным явно несвязанным изменением.

Если вам нужно преобразовать *От 1003 * до PtrImage просто скажите, что вы хотите построить shared_ptr<T> из T. Есть 2 стандартных способа: копирование или перемещение, и в любом случае shared_ptr владеет своим объектом.

В вашем примере, поскольку Image возвращает только ссылку lvalue, вы можете использовать только копию.Вы можете выйти из VecImage, вступив во владение его data участником.

...