C++中的智能指针类别

59 篇文章 0 订阅
52 篇文章 1 订阅

目录

摘要

std::unique_ptr

std::shared_ptr

std::weak_ptr

补充:

std::make_unique

std::make_shared

其它

管理动态内存

总结


摘要

C++中的智能指针是用来管理动态内存的对象,避免我们手动管理内存时可能会带来的复杂性和错误。C++标准库提供了几种不同类型的智能指针,包括`std::unique_ptr`、`std::shared_ptr`和`std::weak_ptr`。

std::unique_ptr

1. `std::unique_ptr`是独占所有权的智能指针,即同一时间只能有一个`std::unique_ptr`指向特定的对象。
2. 当`std::unique_ptr`被销毁时,它所管理的对象会被自动释放。
3. 不能复制`std::unique_ptr`,只能移动它。
4. 当`std::unique_ptr`超出作用域时,它会自动释放资源。
5. 避免从原始指针创建多个`std::unique_ptr`,这会导致双重释放问题。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() {
        std::cout << "MyClass Constructor" << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass Destructor" << std::endl;
    }
    void show() {
        std::cout << "MyClass show" << std::endl;
    }
};

void uniquePtrExample() {
    std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
    ptr->show();

    // 移动所有权
    std::unique_ptr<MyClass> ptr2 = std::move(ptr);
    if (!ptr) {
        std::cout << "ptr is null after move" << std::endl;
    }
    ptr2->show();
}

int main() {
    uniquePtrExample();
    return 0;
}

std::shared_ptr

1. `std::shared_ptr`是共享所有权的智能指针,即可以有多个`std::shared_ptr`指向同一个对象。
2. 当最后一个`std::shared_ptr`被销毁时,对象会被自动释放。
3. `std::shared_ptr`使用引用计数来管理对象,当引用计数为零时,释放对象。
4. 避免循环引用(Circular Reference),这会导致内存泄漏。使用`std::weak_ptr`解决这个问题。
5. 使用`std::make_shared`创建`std::shared_ptr`,这可以减少内存分配的次数并提高性能。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() {
        std::cout << "MyClass Constructor" << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass Destructor" << std::endl;
    }
    void show() {
        std::cout << "MyClass show" << std::endl;
    }
};

void sharedPtrExample() {
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
    {
        std::shared_ptr<MyClass> ptr2 = ptr1;
        ptr2->show();
        std::cout << "Reference count: " << ptr1.use_count() << std::endl;
    }
    std::cout << "Reference count after scope: " << ptr1.use_count() << std::endl;
}

int main() {
    sharedPtrExample();
    return 0;
}

std::weak_ptr

1. `std::weak_ptr`是一个不拥有所有权的智能指针,它用于监视`std::shared_ptr`的生命周期。
2. `std::weak_ptr`不会影响`std::shared_ptr`的引用计数,主要用于避免循环引用。
3. `std::weak_ptr`不能直接访问对象,需要通过`lock`方法获取`std::shared_ptr`来访问对象。
4. `std::weak_ptr`用于打破`std::shared_ptr`的循环引用。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() {
        std::cout << "MyClass Constructor" << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass Destructor" << std::endl;
    }
    void show() {
        std::cout << "MyClass show" << std::endl;
    }
};

void weakPtrExample() {
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
    std::weak_ptr<MyClass> weakPtr = ptr1;

    if (auto sharedPtr = weakPtr.lock()) {
        sharedPtr->show();
        std::cout << "Reference count: " << sharedPtr.use_count() << std::endl;
    } else {
        std::cout << "The managed object has been deleted." << std::endl;
    }
}

int main() {
    weakPtrExample();
    return 0;
}

补充:

`std::make_unique`和`std::make_shared`分别是C++14和C++11时期引入的工厂函数,用于创建智能指针对象。提供了一种安全、高效的方式来分配内存并初始化智能指针,从而减少我们手动使用`new`带来的错误风险。

std::make_unique

`std::make_unique`用于创建一个`std::unique_ptr`实例。

1. 防止内存泄漏:

使用`std::make_unique`可以防止在内存分配和对象构造之间发生异常时的内存泄漏问题。

2. 安全方面:

相比手动使用`new`,`std::make_unique`更加安全,不会产生裸指针。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int x) : value(x) {
        std::cout << "MyClass Constructor, value: " << value << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass Destructor" << std::endl;
    }
    void show() {
        std::cout << "Value: " << value << std::endl;
    }
private:
    int value;
};

void uniquePtrExample() {
    std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(42);
    ptr->show();
}

int main() {
    uniquePtrExample();
    return 0;
}

std::make_shared

`std::make_shared`用于创建一个`std::shared_ptr`实例。

1. 单次内存分配:

`std::make_shared`通过一次内存分配同时创建控制块和对象,从而减少了内存分配的次数,提升了性能。

2. 防止内存泄漏:

使用`std::make_shared`可以防止在内存分配和对象构造之间发生异常时的内存泄漏问题。

3. 简洁和安全:

相比手动使用`new`,`std::make_shared`更加简洁且安全,不会产生裸指针。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int x) : value(x) {
        std::cout << "MyClass Constructor, value: " << value << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass Destructor" << std::endl;
    }
    void show() {
        std::cout << "Value: " << value << std::endl;
    }
private:
    int value;
};

void sharedPtrExample() {
    std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(42);
    ptr->show();
}

int main() {
    sharedPtrExample();
    return 0;
}

其它

`std::make_shared`通过一次内存分配同时创建控制块和对象,提升了性能,但如果不需要共享所有权,可以优先选择`std::make_unique`。

管理动态内存

我们使用`std::make_shared`创建了树状结构的节点,并使用智能指针来管理节点的生命周期。通过`std::make_shared`,我们确保了节点在超出作用域时会自动释放内存,避免了内存泄漏。

#include <iostream>
#include <memory>
#include <vector>

class Node {
public:
    Node(int value) : value(value) {
        std::cout << "Node Constructor, value: " << value << std::endl;
    }
    ~Node() {
        std::cout << "Node Destructor, value: " << value << std::endl;
    }
    void addChild(std::shared_ptr<Node> child) {
        children.push_back(child);
    }
    void show() const {
        std::cout << "Node value: " << value << ", children: ";
        for (const auto& child : children) {
            std::cout << child->value << " ";
        }
        std::cout << std::endl;
    }
private:
    int value;
    std::vector<std::shared_ptr<Node>> children;
};

void treeExample() {
    auto root = std::make_shared<Node>(1);
    auto child1 = std::make_shared<Node>(2);
    auto child2 = std::make_shared<Node>(3);

    root->addChild(child1);
    root->addChild(child2);

    root->show();
    child1->show();
    child2->show();
}

int main() {
    treeExample();
    return 0;
}

总结

1. 使用`std::make_unique`和`std::make_shared`:
   优先使用`std::make_unique`和`std::make_shared`来创建智能指针,避免手动使用`new`,可以提高代码的安全性和性能。

2. 避免循环引用:
   在使用`std::shared_ptr`时要特别小心循环引用的问题。可以使用`std::weak_ptr`来打破循环引用。

3. 注意生命周期:
   确保智能指针的生命周期管理正确,避免悬空指针和内存泄漏。

4. 考虑性能:
   虽然智能指针极大地简化了内存管理,但也带来了额外的开销,如引用计数的维护。因此,在性能敏感的代码中,应慎重使用`std::shared_ptr`。

  • 41
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉夢志昂丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值