为什么 shared_ptr 没有使原始指针为 NULL?

问题描述 投票:0回答:1

我想更好地理解shared_ptr 这是我的代码

struct A {
  int val_ = 0;
  A(int val) : val_(val) { std::cout << "A(" << val_ << ")" << std::endl ; }
  ~A() { std::cout << "~A(" << val_ << ")" << std::endl ; }

};

int main() {
  {
    A* a_raw  = new A(2);
    shared_ptr<A> a2(a_raw); 
    {
      shared_ptr<A> a3(new A(3));
      std::cout << "log 2" << std::endl;
      a2 = a3;
      std::cout << "log 3" << std::endl;
    }
    std::cout << "log 4" << std::endl;
    if (a_raw == nullptr) {
        cout << "A_raw is nullptr" << std::endl;
    } else {
        cout << "A_raw ---------" << a_raw->val_ << std::endl;
    }
  }

电流输出

A(2)
A(3)
log 2
~A(2)
log 3
log 4
A_raw ---------0
~A(3)

Destructor ~A(2) 被调用是因为行

a2 = a3;
你能详细说明
operator=
的逻辑吗?

为什么我看到线

A_raw ---------0
?? 我期待
A_raw is nullptr

我是否正确理解了复制作业

class my_shared_ptr {
    ...
    my_shared_ptr& operator=(const my_shared_ptr& other) {
        if (counter_ and *counter_ > 1) {
            *counter_ -= 1;
        } else {
            delete ptr_;
        }
        
        ptr_ = other.ptr_;
        counter_ = other.counter_;
        if (other.ptr_ != nullptr) {
            *counter_ += 1;
        }
    }
private:
    T* ptr_ = nullptr;
    size_t* counter_ = nullptr;

c++ shared-ptr smart-pointers
1个回答
3
投票

a_raw
不是
nullptr
的问题与作业无关
a3=a2

A* a_raw  = new A(2);
将在空闲存储上分配一个新的 A 并且堆栈上将有一些内存保存该对象的地址。

shared_ptr<A> a2(a_raw);
将按值获取该地址。这样它就是地址的副本,
a2
无法修改原始
a_raw
.

因此永远不可能将

a_raw
设置为
nullptr


作业

a2 = a3
是做什么的?

嗯,operator = 说:

用 r 管理的对象替换被管理的对象。

如果 *this 已经拥有一个对象,并且它是最后一个拥有它的 shared_ptr,并且 r 与 *this 不同,则通过拥有的删除器销毁该对象。

因此,在接管新所有权之前,

a2
将减少资源的引用计数。在您的例子中,引用计数下降到 0,因此对象 A(2) 被销毁。

然后它获得

a3
的所有权,这将引用计数从 1 增加到 2,因为
a2
a3
现在管理相同的资源。您已成功共享一个指针 - 这正是
shared_ptr
所做的。

如前所述,共享指针无法将您的原始

a_raw
设置为
nullptr
,因为它们没有对它的引用。


智能指针的想法是你根本不用处理原始指针。你应该能够完全摆脱

A*
。所以最好一开始就不要有原始指针:

int main() {
{
    shared_ptr<A> a2(new A(2)); 
    {
      shared_ptr<A> a3(new A(3));
      std::cout << "log 2" << std::endl;
      a2 = a3;
      std::cout << "log 3" << std::endl;
    }
    std::cout << "log 4" << std::endl;
}

甚至使用

make_shared
这样您就永远不会尝试为您的
delete
语句搜索匹配的
new
语句。

int main() {
{
    shared_ptr<A> a2 = make_unique<A>(2); 
    {
      shared_ptr<A> a3= make_unique<A>(3);
      std::cout << "log 2" << std::endl;
      a2 = a3;
      std::cout << "log 3" << std::endl;
    }
    std::cout << "log 4" << std::endl;
}

关于复制分配的更新问题:

  • 从给定的代码中,我看不到

    counter_
    在哪里初始化。

  • 该方法缺少

    return
    语句,它返回的内容非常重要。

  • *counter_ -= 1;
    - 如果在这个操作之后计数器
    == 0
    ,指针应该是
    delete
    d.

  • nullptr
    中检查
    if (other.ptr_ != nullptr)
    是没有必要的,恕我直言。由于您可以
    delete
    nullptr
    ,您只需像其他任何指针一样跟踪它的引用。

© www.soinside.com 2019 - 2024. All rights reserved.