Подтвердить что ты не робот

Как выпустить указатель из boost:: shared_ptr?

Может ли boost:: shared_ptr освобождать сохраненный указатель без его удаления?

Я вижу, что в документации отсутствует функция release, также в FAQ часто объясняется, почему она не предоставляет функцию выпуска, что-то вроде того, что релиз не может быть выполнен по указателям, которые не уникальны. Мои указатели уникальны. Как я могу освободить свои указатели? Или, что стимулирует класс интеллектуального указателя, который позволит мне освободить указатель? Я надеюсь, что вы не будете использовать auto_ptr:)

4b9b3361

Ответ 1

Вам нужно использовать дебетер, который вы можете запросить, чтобы не удалить основной указатель.

См. этот ответ (который был отмечен как дубликат этого вопроса) для получения дополнительной информации.

Ответ 2

не делать. Boost FAQ:

Q. Почему shared_ptr не предоставляет функцию release()?

А. shared_ptr не может отдать право собственности, если оно не уникально(), потому что другая копия все равно уничтожит объект.

Рассмотрим:

shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2

int * p = a.release();

// Who owns p now? b will still call delete on it in its destructor.

Кроме того, указатель, возвращаемый release(), будет трудно освободить навсегда, поскольку исходный shared_ptr мог быть создан с пользовательским удалением.

Итак, это было бы безопасно, если бы это единственный экземпляр shared_ptr, указывающий на ваш объект (когда unique() возвращает true), и объект не требует специального делетера. Я бы по-прежнему задавал вопрос о вашем дизайне, если вы использовали такую ​​функцию .release().

Ответ 3

Вы можете использовать поддельный дебетер. Тогда указатели не будут удалены фактически.

struct NullDeleter {template<typename T> void operator()(T*) {} };

// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );

Ответ 4

Дети, не делайте это дома:

// set smarty to point to nothing
// returns old(smarty.get())
// caller is responsible for the returned pointer (careful)
template <typename T>
T* release (shared_ptr<T>& smarty) {
    // sanity check:
    assert (smarty.unique());
    // only one owner (please don't play games with weak_ptr in another thread)
    // would want to check the total count (shared+weak) here

    // save the pointer:
    T *raw = &*smarty;
    // at this point smarty owns raw, can't return it

    try {
        // an exception here would be quite unpleasant

        // now smash smarty:
        new (&smarty) shared_ptr<T> ();
        // REALLY: don't do it!
        // the behaviour is not defined!
        // in practice: at least a memory leak!
    } catch (...) {
        // there is no shared_ptr<T> in smarty zombie now
        // can't fix it at this point:
        // the only fix would be to retry, and it would probably throw again
        // sorry, can't do anything
        abort ();
    }
    // smarty is a fresh shared_ptr<T> that doesn't own raw

    // at this point, nobody owns raw, can return it
    return raw;
}

Теперь, есть ли способ проверить, является ли общее количество владельцев для количества ссылок > 1?

Ответ 5

Чтобы указатель больше ничего не указывал, вы можете вызвать shared_ptr::reset().

Однако это приведет к удалению объекта, на который указывает, когда ваш указатель является последней ссылкой на объект. Это, однако, является именно желательным поведением смарт-указателя в первую очередь.

Если вам просто нужна ссылка, которая не удерживает объект в живых, вы можете создать boost::weak_ptr (см. ускорить документирование). A weak_ptr содержит ссылку на объект, но не добавляет к счетчику ссылок, поэтому объект удаляется, когда существуют только слабые ссылки.

Ответ 6

Основой разделения является доверие. Если какой-то экземпляр вашей программы должен освободить необработанный указатель, почти наверняка будет shared_ptr неправильный тип.

Однако в последнее время я тоже хотел это сделать, поскольку мне нужно было освободиться от другого процесса-кучи. В конце концов меня учили, что мое прежнее решение использовать некоторые std::shared_ptr не было продумано.

Я просто использовал этот тип для очистки. Но указатель был просто дублирован на несколько мест. На самом деле мне понадобился std::unique_ptr, который (suprise) имеет функцию release.

Ответ 7

Простите их, потому что они не знают, что они делают. Этот пример работает с boost:: shared_ptr и msvs std:: shared_ptr без утечек памяти!

template <template <typename> class TSharedPtr, typename Type>
Type * release_shared(TSharedPtr<Type> & ptr)
{
    //! this struct mimics the data of std:shared_ptr ( or boost::shared_ptr )
    struct SharedVoidPtr
    {
        struct RefCounter
        {
            long _Uses;
            long _Weaks;
        };

        void * ptr;
        RefCounter * refC;

        SharedVoidPtr()
        {
            ptr = refC = nullptr;
        }

        ~SharedVoidPtr()
        {
            delete refC;
        }
    };

    assert( ptr.unique() );

    Type * t = ptr.get();

    SharedVoidPtr sp; // create dummy shared_ptr
    TSharedPtr<Type> * spPtr = (TSharedPtr<Type>*)( &sp );
    spPtr->swap(ptr); // swap the contents

    ptr.reset();
    // now the xxx::shared_ptr is empy and
    // SharedVoidPtr releases the raw poiter but deletes the underlying counter data
    return t;
}

Ответ 8

Вы можете удалить общий указатель, который кажется мне таким же. Если указатели всегда уникальны, то std::auto_ptr<> - хороший выбор. Имейте в виду, что уникальные указатели не могут использоваться в контейнерах STL, поскольку операции с ними делают много копий и временное дублирование.

Ответ 9

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

template<typename T>
T * release_shared(std::shared_ptr<T> & shared)
{
    static std::vector<std::shared_ptr<T> > graveyard;
    graveyard.push_back(shared);
    shared.reset();
    return graveyard.back().get();
}

Ответ 10

Если ваши указатели действительно уникальны, используйте std::unique_ptr или boost::scoped_ptr, если первое не доступно для вашего компилятора. В противном случае рассмотрим объединение boost::shared_ptr с boost::weak_ptr. Подробнее см. Boost documentation.

Ответ 11

Я использую Poco:: HTTPRequestHandlerFactory, который ожидает возврата необработанного HTTPRequestHandler *, среда Poco удаляет обработчик после завершения запроса.

Также, используя проект DI Sauce для создания контроллеров, однако Injector возвращает shared_ptr, который я не могу вернуть напрямую, и возврат handler.get() не является хорошим либо с тех пор, как только эта функция возвращает shared_ptr выходит за пределы области действия и удаляет обработчик до его выполнения, поэтому разумная (я думаю) причина иметь метод .release(). Я закончил создание класса HTTPRequestHandlerWrapper следующим образом: -

class HTTPRequestHandlerWrapper : public HTTPRequestHandler {
private:
    sauce::shared_ptr<HTTPRequestHandler> _handler;

public:
    HTTPRequestHandlerWrapper(sauce::shared_ptr<HTTPRequestHandler> handler) {
        _handler = handler;
    }

    virtual void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) {
        return _handler->handleRequest(request, response);
    }
};

а затем factory будет

HTTPRequestHandler* HttpHandlerFactory::createRequestHandler(const HTTPServerRequest& request) {
    URI uri = URI(request.getURI());
    auto path = uri.getPath();
    auto method = request.getMethod();

    sauce::shared_ptr<HTTPRequestHandler> handler = _injector->get<HTTPRequestHandler>(method + ":" + path);

    return new HTTPRequestHandlerWrapper(handler);
}

которые удовлетворяли как Соус, так и Поко и прекрасно работали.

Ответ 12

Мне нужно было передать указатель через асинхронные обработчики и сохранить поведение самоуничтожения в случае сбоя, но конечный API ожидал необработанный указатель, поэтому я сделал эту функцию для выпуска из одного shared_ptr:

#include <memory>

template<typename T>
T * release(std::shared_ptr<T> & ptr)
{
    struct { void operator()(T *) {} } NoDelete;

    T * t = nullptr;
    if (ptr.use_count() == 1)
    {
        t = ptr.get();
        ptr.template reset<T>(nullptr, NoDelete);
    }
    return t;
}

Если ptr.use_count() != 1, вы получите вместо него nullptr.

Ответ 13

Я не совсем уверен, что ваш вопрос заключается в достижении этого, но если вам нужно поведение от shared_ptr, где, если вы отпустите значение из одного shared_ptr, все остальные общие указатели на одно и то же значение стать nullptr, тогда вы можете поместить unique_ptr в shared_ptr для достижения этого поведения.

void print(std::string name, std::shared_ptr<std::unique_ptr<int>>& ptr)
{
    if(ptr == nullptr || *ptr == nullptr)
    {
        std::cout << name << " points to nullptr" << std::endl;
    }
    else
    {
        std::cout << name << " points to value " << *(*ptr) << std::endl;
    }
}

int main()
{
    std::shared_ptr<std::unique_ptr<int>> original;
    original = std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(50));

    std::shared_ptr<std::unique_ptr<int>> shared_original = original;

    std::shared_ptr<std::unique_ptr<int>> thief = nullptr;

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    thief = std::make_shared<std::unique_ptr<int>>(original->release());

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    return 0;
}

Вывод:

original points to value 50
shared_original points to value 50
thief points to nullptr
original points to nullptr
shared_original points to nullptr
thief points to value 50

Такое поведение позволяет вам совместно использовать ресурс (например, массив), а затем повторно использовать этот ресурс, недействив все общие ссылки на этот ресурс.

Ответ 14

Простое решение, увеличьте ссылочку и затем пропустите shared_pointer.

boost::shared_ptr<MyType> shared_pointer_to_instance(new MyType());
new boost::shared_ptr<MyType>();
MyType * raw_pointer = shared_pointer_to_instance.get()

Это явно вызовет утечку памяти как shared_ptr, так и MyType *