【问题标题】:How to get the pointer to a shared_ptr?如何获取指向 shared_ptr 的指针?
【发布时间】:2010-03-03 13:10:09
【问题描述】:

我现在正在破解一个旧的 C 代码,试着让它更像 C++/Boost 风格:

有一个资源分配函数长这样:

my_src_type* src;
my_src_create(&src, ctx, topic, handle_src_event, NULL, NULL);

我尝试用 shared_ptr 包装 src:

shared_ptr<my_src_type> pSrc;

刚才忘记说了。我需要这样做作为一个循环

std::map<string, shared_ptr<my_src_type>  > dict;
my_src_type* raw_ptr;

BOOST_FOREACH(std::string topic, all_topics)
{
    my_src_create(&raw_ptr, ctx, topic, handle_src_event, NULL, NULL);
    boost::shared_ptr<my_src_type> pSrc(raw_ptr);
    dict[topic] = pSrc;
}

我可以这样吗?

【问题讨论】:

  • 我很惊讶没有人提到 boost::shared_ptr 的删除器功能。

标签: c++ boost shared-ptr


【解决方案1】:

在 C 样式资源上使用 shared_ptr

使用boost::shared_ptr,您可以将函数指针传递给“删除器”,当引用计数达到零时,该删除器将被自动调用。此功能允许使用 shared_ptr 来管理旧版 C API 返回的资源。

考虑保留您的旧版my_src_create,并提供一个返回shared_ptr 的新“工厂”函数:

void my_src_deleter(my_src_type* raw_ptr)
{
    my_src_destroy(raw_ptr);
}

typedef boost::shared_ptr<my_src_type> my_src_shared_ptr;

my_src_shared_ptr create_my_src(...)
{
    my_src_type* raw_ptr;
    my_src_create(&raw_ptr, ctx, topic, handle_src_event, NULL, NULL);
    return my_src_shared_ptr(raw_ptr, &my_src_deleter);
}

std::map<string, my_src_shared_ptr> dict;

BOOST_FOREACH(std::string topic, all_topics)
{
    dict[topic] = create_my_src(ctx, topic, handle_src_event, NULL, NULL);
}

将传统 C 结构/函数包装在一个类中

或者,(如 jpalecek 建议的那样)您可以将 my_src 包装在一个类中。遗留my_src 对象的创建和销毁在构造函数和析构函数中处理。如果你打算这样做,你应该考虑你是否希望你的MySrc 类是可复制的。如果MySrc 是重量级的或创建成本很高,您可能希望使其不可复制并考虑使用shared_ptr&lt;MySrc&gt; 如果要共享MySrc 的所有权:

class MySrc
{
public:
    typedef boost::shared_ptr<MySrc> Ptr;
    MySrc(...) { my_src_create(&src_, ...); }
    ~MySrc() { my_src_destroy(&src_); }
    // Other member functions that uses my_src legacy functions

private:
    my_src_type* src_;
    // Make copy-constructor and assignment private to disallow copies
    MySrc(const MySrc& rhs) {}
    MySrc& operator=(const MySrc& rhs) {return *this;}
};

std::map<string, MySrc::Ptr> dict;

BOOST_FOREACH(std::string topic, all_topics)
{
    dict[topic] = MySrc::Ptr(
        new MySrc(ctx, topic, handle_src_event, NULL, NULL) );
}

请注意,您还可以使用 MySrc 类来包装对 my_src 实例进行操作的遗留函数。

如果您希望 MySrc 可复制,请确保实现复制构造函数和赋值运算符,以便执行深度复制。

【讨论】:

    【解决方案2】:

    没有。

    基本上,您必须使用旧的 C 方式,然后以某种方式将结果转换为 shared_pointer

    你可以通过简单的初始化 shared_pointer 来做到这一点

    my_src_type* pSrc;
    my_src_create(&src, ctx, topic, handle_src_event, NULL, NULL);
    shared_ptr<my_src_type> sp(pSrc);
    

    但请注意,如果my_src_create 函数可以返回一个已经存在的对象,这将失败。另外,如果有my_src_destroy函数,它也不会被调用。

    恕我直言,最简洁的方法是将结构包装在 C++ 类中:

    class MySrc {
      my_src_type* pSrc;
    public:
      MySrc(...) { my_src_create(&pSrc, ...); }
      ~MySrc() { my_src_destroy(&pSrc); }
    private:
      MySrc(const MySrc&);
      void operator=(const MySrc&); // disallow copying
    };
    

    然后以通常的方式为MySrc 使用共享指针。

    【讨论】:

    • 在第一个块中,采用原始指针的共享指针构造函数是显式的,因此您必须使用显式初始化:shared_ptr&lt;my_src_type&gt; sp(pSrc); 而不是shared_ptr&lt;my_src_type&gt; sp=pSrc;(还有shared_ptr 拼写错误)
    • 在您的第二个 sn-p 中,您应该使类不可复制,或者覆盖默认的复制构造函数和赋值运算符以执行深度复制。
    • @David Rodríguez - dribeas,@Emile Cormier:谢谢,在编辑中反映了您的反对意见。
    【解决方案3】:

    我认为你的问题没有多大意义。如果 my_src_create 正在被重做,则传递对共享指针的引用,或者返回共享指针。如果您不修改该方法,那么您将无法真正做到。我建议使用原始指针进行创建,然后将其包装成共享指针:

    shared_ptr<my_src_type> src;
    {
       my_src_type* raw_src;
       my_src_create(&raw_src, ctx, topic, handle_src_event, NULL, NULL);
       src.reset( raw_src ); // hand ownership to shared_ptr
    }
    

    获取共享指针内部的指针并对其进行修改会破坏共享指针不变量:您将更改指针但不会更新共享计数。

    【讨论】:

      【解决方案4】:

      你也在重做my_src_create()吗?

      鉴于函数的名称,我会返回一个 boost::shared_ptr 而不是传入一个预先构建的函数,因为恕我直言,这样更清晰、更干净。除非该函数还返回某种失败/成功代码,但最好通过抛出异常来处理。

      如果你非常想传入一个空的 shared_ptr,你可以通过非常量引用传入它,并在 my_src_create 中使用 shared_ptr::reset() 为其分配一个新值。

      【讨论】:

        【解决方案5】:

        您始终可以“按旧方式”执行此操作,然后使用 reset()make_shared()src 指针分配给 shared_ptr。

        【讨论】:

          【解决方案6】:

          我会用这段代码来解决你的问题:

          my_src_type* src;
          my_src_create(&src, ctx, topic, handle_src_event, NULL, NULL);
          boost::shared_ptr<my_src_type> pSrc(src);
          

          从那时起,pSrc 将管理 my_src_type* src 指向的分配内存。

          编辑:删除我答案的错误部分。

          【讨论】:

          • 第二个版本无效:pSrc.get() 返回指针的副本,而不是实际的指针。修改它不会在共享指针内产生影响
          • 是的,我知道。没有检查就把它放在我的头上。在世界的这些地方还为时过早:) 我把它删掉了。
          猜你喜欢
          • 2021-11-15
          • 1970-01-01
          • 2021-11-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多