如何将原始指针包装到shared_ptr并阻止shared_ptr删除对象?

时间:2013-03-20 20:34:41

标签: c++ shared-ptr

我需要将原始指针包装到shared_ptr中,以便将其传递给函数。一旦返回,该函数就不会对输入对象进行任何引用。

{
  MyClass i;
  shared_ptr<MyClass> p(&i);
  f(p);
  // BAD: shared_ptr will delete i.
}

如何防止shared_ptr删除引用的对象?

2 个答案:

答案 0 :(得分:4)

在评论中提到chris,写一个空的删除器:

#include <type_traits>

template <typename T>
struct empty_delete
{
    empty_delete() /* noexcept */
    {
    }

    template <typename U>
    empty_delete(const empty_delete<U>&,
        typename std::enable_if<
            std::is_convertible<U*, T*>::value
        >::type* = nullptr) /* noexcept */
    {
    }

    void operator()(T* const) const /* noexcept */
    {
        // do nothing
    }
};

使用示例:

#include <iostream>
#include <memory>

struct noisy
{
    noisy() { std::cout << "alive" << std::endl; }
    ~noisy() { std::cout << "dead" << std::endl; }

    noisy(const noisy&);
    noisy& operator=(const noisy&);
};

template <typename T>
void take(T& yours)
{
    std::cout << "Taking..." << std::endl;
    {
        auto mine = std::move(yours);
    }
    std::cout << "Took." << std::endl;
}

int main()
{
    std::unique_ptr<noisy> a(new noisy());
    std::shared_ptr<noisy> b(new noisy());
    std::unique_ptr<noisy, empty_delete<noisy>> c(new noisy());
    std::shared_ptr<noisy> d(new noisy(), empty_delete<noisy>());

    take(a);
    take(b);
    take(c);
    take(d);
}

输出:

  


  活着
  活着
  活着
  以...
  死
  拿了。
  以...
  死
  拿了。
  以...
  拿了。
  以...
  拿。

当然,这个例子会泄漏内存。

答案 1 :(得分:0)

对于注释中提到的.NET / clr,您应该实现ref class,传递托管句柄^,并让垃圾收集器管理生存期。

ref class MyClassManaged : public Pen
{
public:
  MyClassManaged() : Pen{}, native_{ new MyClass{} } { }
  ~MyClassManaged() { this->!MyClassManaged(); }
  !MyClassManaged() { delete native_; }
private:
  MyClass* native_;
};
//...
{
  MyClassManaged^ i = gcnew MyClassManaged{};
  fManaged(i);
}

TL; DR只需保留shared_ptr<MyClass>的另一个副本,并在堆上分配i即可,如果您仍然需要,也可以在堆栈上分配。{strong>

场景1

{
  shared_ptr<MyClass> another_p;
  {
    MyClass i;
    shared_ptr<MyClass> p(&i);
    f(p);
    // p has not deleted i yet
    another_p = p; // increment reference count
    // p will decrement the reference count
    // i will be deleted due to stack unwinding
  }
  // another_p still holds a reference to where i was on the stack
  if (another_p)
    something(); // yes, something() will be invoked
  else
    nothing(); // no, nothing() won't run here
  // another_p will attempt to delete again if not the shared_ptr is not copied elsewhere
}

场景2

{
  shared_ptr<MyClass> another_p;
  {
    auto p = make_shared<MyClass>();
    auto& i = *p;
    f(p);
    // p has not deleted i
    another_p = p; // increment reference count
    // p will decrement the reference count
    // i will be NOT deleted
  }
  // another_p still holds a reference to where i was on the heap
  if (another_p)
    something(); // yes, something() will be invoked
  else
    nothing(); // no, nothing() won't run here
  // another_p will attempt to delete again if not the shared_ptr is not copied elsewhere
}
// it will finally be deleted now

只需保持另一个shared_ptr副本有效即可;无需弄乱空的删除器。