Обёртывание C ++ / CLI функции, которая возвращает std :: shared_ptr - PullRequest
3 голосов
/ 30 мая 2011

В настоящее время я обертываю класс C ++ с C ++ / CLI для взаимодействия .NET, следуя стандартному процессу удержания собственного указателя в управляемом классе. В одном случае у меня есть нативный класс, который имеет такую ​​функцию:

std::shared_ptr<BaseChannel> channelData(const int RunNumber);

Я уже начал создавать класс-оболочку для BaseChannel. Однако, если я передам необработанный указатель в конструктор управляемого класса, нет никаких гарантий относительно времени жизни объекта, на который указывает управляемый класс. То есть shared_ptr может выйти из области видимости, и объект будет удален, а управляемый класс останется с висящим указателем.

Какое общее решение для этой ситуации?

UPDATE

@ Ben: Итак, я обертываю класс, который содержит метод в приведенном выше вопросе, примерно так (скажем, он находится в собственном классе с именем Node и упакован в управляемый класс с именем NodeRef:

ChannelUser^ NodeRef::ChannelData(int runNumber)
{
    // mpNode is native class pointer of type Node held in managed class
    // wrapper called NodeRef
    std::shared_ptr<BaseChannel> spBaseChannel = mpNode->channelData(runNumber);

    // ChannelUser is using clr_scoped_ptr to hold the shared_ptr
    ChannelUser^ channelUser = gcnew ChannelUser(spBaseChannel);
    return channelUser;
}

Поскольку для shared_ptr количество ссылок не увеличивается, поскольку он передается в управляемый класс по ссылке, означает ли это

что пока этот shared_ptr находится в сфера, объект, на который он указывает воля до сих пор существует, потому что его ссылка количество будет не менее 1

? (ref C ++ - передача ссылок на std :: shared_ptr или boost :: shared_ptr )

Ответы [ 2 ]

10 голосов
/ 01 октября 2012

Вот управляемый shared_ptr<T>. Вы можете назначить ему напрямую из shared_ptr, и он возьмет копию, которую он удалит, когда управляемый объект будет удален или удален.

Примеры:

m_shared_ptr<CupCake> cupCake0(new CupCake());
m_shared_ptr<CupCake> cupCake1 = new CupCake();
m_shared_ptr<CupCake> cupCake2 = shared_ptr<CupCake>(new CupCake());
m_shared_ptr<CupCake> cupCake3 = make_shared<CupCake>();
shared_ptr<CupCake> cupCake4 = (shared_ptr<CupCake>)cupCake3;

Код:

#pragma once

#include <memory>

template <class T>
public ref class m_shared_ptr sealed
{
    std::shared_ptr<T>* pPtr;

public:
    m_shared_ptr() 
        : pPtr(new std::shared_ptr<T>()) 
    {}

    m_shared_ptr(T* t) {
        pPtr = new std::shared_ptr<T>(t);
    }

    m_shared_ptr(std::shared_ptr<T> t) {
        pPtr = new std::shared_ptr<T>(t);
    }

    m_shared_ptr(const m_shared_ptr<T>% t) {
        pPtr = new std::shared_ptr<T>(*t.pPtr);
    }

    !m_shared_ptr() {
        delete pPtr;
    }

    ~m_shared_ptr() {
        delete pPtr;
    }

    operator std::shared_ptr<T>() {
        return *pPtr;
    }

    m_shared_ptr<T>% operator=(T* ptr) {
        delete pPtr;
        pPtr = new std::shared_ptr<T>(ptr);
        return *this;
    }

    T* operator->() {
        return (*pPtr).get();
    }

    void reset() {
        pPtr->reset();
    }
};
6 голосов
/ 30 мая 2011

shared_ptr - это собственный тип, и управляемые объекты не могут иметь встроенных собственных подобъектов.

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

Конечно, есть много причин для использования интеллектуальногоуказатель вместо необработанного shared_ptr<BaseChannel>*.Я написал умный указатель, который должен быть подходящим, вы можете найти его на codereview.stackexchange.com: "scoped_ptr для C ++ / CLI (убедитесь, что управляемый объект должным образом освобождает собственный объект)"


Пример (не протестирован на компиляцию):

ref class ChannelUser
{
    clr_scoped_ptr<shared_ptr<BaseChannel>> chan_ptr;

public:
    ChannelUser( shared_ptr<BaseChannel>& chan ) : chan_ptr(new shared_ptr<BaseChannel>(chan)) {}
};

Это автоматически реализует IDisposable и удаляет shared_ptr при запуске Dispose или финализаторе, что, в свою очередь, уменьшает счетчик ссылок наBaseChannel.

...