如何使用带有指向不应释放的struct的指针的shared_ptr

时间:2015-12-06 18:40:51

标签: c++ pointers c++11 shared-ptr

目前我正在使用glib库中的一些函数。随着glib也来了gio。 glib是一个C库,因此我需要删除一些我创建的结构。

对于我创建智能指针的许多对象,例如:

std::shared_ptr<GAsyncQueue> my_queue = std::shared_ptr<GAsyncQueue>(g_async_queue_create(), g_async_queue_unref);

为此创建了一个指向GAsyncQueue的共享指针,这可以安全地在其生​​命周期结束时销毁队列。

但是,当我从gio库获取一个我不应该释放的指针时遇到问题。在下面的代码中,my_connection是一个GSocketClient,它实现了(在glib中)GIOStream。

std::shared_ptr<GInputStream> my_input_stream = 
     std::shared_ptr<GInputStream> (
        g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()))
     );

因为有关GIOStream的文档提到,不应释放使用g_io_stream_get_input_stream()获取的指针。那是因为它归my_connection实例所有。 我想为destroy对象创建一个lamda,它是共享指针对象的第二个参数。例如auto deleter = [](GInputStream* ptr) {};然后将lambda作为detroy函数提供给共享指针,但这感觉有点愚蠢。

3 个答案:

答案 0 :(得分:12)

嗯,替代no-op删除器可能正在使用别名共享指针

template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;

它共享x,但在get()之后,您将返回p

讨论:What is shared_ptr's aliasing constructor for?

答案 1 :(得分:6)

你可能只是不需要std::shared_ptr。你可能甚至不需要指针。

在我阅读你的问题和评论时,我没有看到任何反对

的观点
auto& my_input_stream = *( g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get())) )

指针允许可选数据。然而,它的确大多使用错误的方式也是如此。具有

void foo( type* ptr)
{
    if (!ptr)
        throw exception;
}

通常没有意义。如果函数必须处理具体数据,则允许NULL参数仅在您担心提供该数据时才有用。否则,只需要对象的引用(可能const)。

智能指针很有用;但他们仍然是指针。如果可能的话,完全避免它们会更好。

来自评论:

  

但是,必须始终初始化引用

绝对。从C ++ 11开始,虽然我们已经获得了std::reference_wrapper,但也可以重新安置并存储在容器中。

答案 2 :(得分:5)

您可以使用不执行任何操作的删除器类型,但需要将其作为参数传递给shared_ptr的构造函数

struct DoNothing {
    template <typename T>
    void operator()(T*) const noexcept { }
};

创建shared_ptr时,您需要创建其中一个删除器并将其传递给构造函数(因为您正在使用lambda)。您可以使用中间函数

使自己更容易
template <typename T>
std::shared_ptr<T> non_deleting_shared_ptr(T* ptr) {
    return {ptr, DoNothing};
}

auto my_input_stream = 
    non_deleting_shared_ptr(
        g_io_stream_get_input_stream(G_IO_STREAM(my_connection.get()));

然而,更大的问题是,当您不希望所有权成为其中的一部分时,为什么要使用智能指针。你只需GAsyncQueue*几乎肯定会更好,除非你有shared_ptr需要随时 的情况>。像数据成员一样?