指您不拥有的"std::unique_ptr"(使用原始指针?



通常,如果您使用的是std::shared_ptr指向对象,并且要创建另一个指向该对象的指针,该对象不共享所有权,您将创建std::weak_ptr

// Create a shared pointer to own the object
std::shared_ptr<int> p = std::make_shared<int>(42);
// Create a weak pointer (that does not own the object)
std::weak_ptr<int> q(p);
// Use the weak pointer some time later
if (std::shared_ptr ptr = q.lock()) {
  // use *ptr
}

我的问题是,在std::unique_ptr方面,您如何执行此操作?

使用独特的指针确保当前资源由std::unique_ptr本身独家拥有。但是,如果我想创建一个指向不拥有该资源的相同资源的指针怎么办?我无法使用std::weak_ptr,因为弱指针被设计为与std::shared_ptr的参考计数一起使用。我可以在这里使用原始指针吗?还是有更好的选择?

// Create a unique pointer to own the object
std::unique_ptr<int> p = std::make_unique<int>(42);
// Create a non-owning pointer to the same object
// Is this really the best way?
int* q = p.get();
// Use the pointer some time later
if (q != nullptr) {
  // Imagine this may be multithreaded...
  // what happens if p.reset() is called by another thread while the current thread is RIGHT HERE.
  // use *q
}

我想到的唯一方法是创建一个非所有人指针,指向std::unique_ptr拥有的对象是使用原始指针,但是从上面的代码中可以看到,这可能会在螺纹应用程序中引起问题。有更好的方法可以实现相同的目标吗?

基于您的上一个示例,这是一种情况,应使用std::shared_ptrstd::weak_ptr

std::unique_ptr和非持有的原始指针应在您有保证智能指针将超过原始指针的情况下使用。

class A {
    std::unique_ptr<int> ptr = std::make_unique<int>(5);
public:
    int* get_ptr() const{return ptr.get();}
};
class B {
    A a;
public:
    void do_something() {
        //int * ptr = a.get_ptr();//Valid, but not advised
        int & ref = *a.get_ptr();//Preferred
        ref++;
    }
};

如果您可以做出此保证,则应使用std::unique_ptr和原始指针来表示此对象。这是明智的。

但是,如果您不能保证在需要操纵对象时使用寿命,则应由std::weak_ptr提供参考,该参考可以用于获取所有权(即使只是暂时!)进行更改。

class A {
    std::shared_ptr<int> ptr = std::make_shared<int>(5);
public:
    std::weak_ptr<int> get_ptr() const {
        return ptr;//Implicitly converts
    }
    void destroy() {
        ptr.reset();
    }
};
class B {
    std::weak_ptr<int> ptr;
public:
    B(std::weak_ptr<int> ptr) : ptr(ptr) {}
    void do_something() {
        if(auto owned_ptr = ptr.lock()) {//owned_ptr will be deduced to be of type std::shared_ptr<int>
            *owned_ptr++; //Guaranteed to only execute if the pointer is still valid
        }
    }
};
int main() {
    A a;
    B b(a.get_ptr());
    if(get_random_value() > 10)
        a.destroy();
    b.do_something();
}

这取决于额外的指针是否可能超过 unique_ptr

  • 如果非持有指针绝对不能超越 unique_ptr:使其成为普通的指针。谁得到这种指针可以假定其有效,但不能假定拥有它指向的内存。
  • 如果非持有指针可能会超过 unique_ptr:您的原始指针并不是真正的"唯一";您应该用shared_ptr替换unique_ptr,然后将weak_ptr作为非持有副本传递。

我只是注意到这个答案基本上是Xirema答案的简短摘要。请投票/接受该答案!

最新更新