当前位置:   article > 正文

C++中的智能指针类别

C++中的智能指针类别

目录

摘要

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`,这会导致双重释放问题。

  1. #include <iostream>
  2. #include <memory>
  3. class MyClass {
  4. public:
  5. MyClass() {
  6. std::cout << "MyClass Constructor" << std::endl;
  7. }
  8. ~MyClass() {
  9. std::cout << "MyClass Destructor" << std::endl;
  10. }
  11. void show() {
  12. std::cout << "MyClass show" << std::endl;
  13. }
  14. };
  15. void uniquePtrExample() {
  16. std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
  17. ptr->show();
  18. // 移动所有权
  19. std::unique_ptr<MyClass> ptr2 = std::move(ptr);
  20. if (!ptr) {
  21. std::cout << "ptr is null after move" << std::endl;
  22. }
  23. ptr2->show();
  24. }
  25. int main() {
  26. uniquePtrExample();
  27. return 0;
  28. }

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`,这可以减少内存分配的次数并提高性能。

  1. #include <iostream>
  2. #include <memory>
  3. class MyClass {
  4. public:
  5. MyClass() {
  6. std::cout << "MyClass Constructor" << std::endl;
  7. }
  8. ~MyClass() {
  9. std::cout << "MyClass Destructor" << std::endl;
  10. }
  11. void show() {
  12. std::cout << "MyClass show" << std::endl;
  13. }
  14. };
  15. void sharedPtrExample() {
  16. std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
  17. {
  18. std::shared_ptr<MyClass> ptr2 = ptr1;
  19. ptr2->show();
  20. std::cout << "Reference count: " << ptr1.use_count() << std::endl;
  21. }
  22. std::cout << "Reference count after scope: " << ptr1.use_count() << std::endl;
  23. }
  24. int main() {
  25. sharedPtrExample();
  26. return 0;
  27. }

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`的循环引用。

  1. #include <iostream>
  2. #include <memory>
  3. class MyClass {
  4. public:
  5. MyClass() {
  6. std::cout << "MyClass Constructor" << std::endl;
  7. }
  8. ~MyClass() {
  9. std::cout << "MyClass Destructor" << std::endl;
  10. }
  11. void show() {
  12. std::cout << "MyClass show" << std::endl;
  13. }
  14. };
  15. void weakPtrExample() {
  16. std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
  17. std::weak_ptr<MyClass> weakPtr = ptr1;
  18. if (auto sharedPtr = weakPtr.lock()) {
  19. sharedPtr->show();
  20. std::cout << "Reference count: " << sharedPtr.use_count() << std::endl;
  21. } else {
  22. std::cout << "The managed object has been deleted." << std::endl;
  23. }
  24. }
  25. int main() {
  26. weakPtrExample();
  27. return 0;
  28. }

补充:

`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`更加安全,不会产生裸指针。

  1. #include <iostream>
  2. #include <memory>
  3. class MyClass {
  4. public:
  5. MyClass(int x) : value(x) {
  6. std::cout << "MyClass Constructor, value: " << value << std::endl;
  7. }
  8. ~MyClass() {
  9. std::cout << "MyClass Destructor" << std::endl;
  10. }
  11. void show() {
  12. std::cout << "Value: " << value << std::endl;
  13. }
  14. private:
  15. int value;
  16. };
  17. void uniquePtrExample() {
  18. std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(42);
  19. ptr->show();
  20. }
  21. int main() {
  22. uniquePtrExample();
  23. return 0;
  24. }

std::make_shared

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

1. 单次内存分配:

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

2. 防止内存泄漏:

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

3. 简洁和安全:

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

  1. #include <iostream>
  2. #include <memory>
  3. class MyClass {
  4. public:
  5. MyClass(int x) : value(x) {
  6. std::cout << "MyClass Constructor, value: " << value << std::endl;
  7. }
  8. ~MyClass() {
  9. std::cout << "MyClass Destructor" << std::endl;
  10. }
  11. void show() {
  12. std::cout << "Value: " << value << std::endl;
  13. }
  14. private:
  15. int value;
  16. };
  17. void sharedPtrExample() {
  18. std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(42);
  19. ptr->show();
  20. }
  21. int main() {
  22. sharedPtrExample();
  23. return 0;
  24. }

其它

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

管理动态内存

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

  1. #include <iostream>
  2. #include <memory>
  3. #include <vector>
  4. class Node {
  5. public:
  6. Node(int value) : value(value) {
  7. std::cout << "Node Constructor, value: " << value << std::endl;
  8. }
  9. ~Node() {
  10. std::cout << "Node Destructor, value: " << value << std::endl;
  11. }
  12. void addChild(std::shared_ptr<Node> child) {
  13. children.push_back(child);
  14. }
  15. void show() const {
  16. std::cout << "Node value: " << value << ", children: ";
  17. for (const auto& child : children) {
  18. std::cout << child->value << " ";
  19. }
  20. std::cout << std::endl;
  21. }
  22. private:
  23. int value;
  24. std::vector<std::shared_ptr<Node>> children;
  25. };
  26. void treeExample() {
  27. auto root = std::make_shared<Node>(1);
  28. auto child1 = std::make_shared<Node>(2);
  29. auto child2 = std::make_shared<Node>(3);
  30. root->addChild(child1);
  31. root->addChild(child2);
  32. root->show();
  33. child1->show();
  34. child2->show();
  35. }
  36. int main() {
  37. treeExample();
  38. return 0;
  39. }

总结

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`。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/666417
推荐阅读
相关标签
  

闽ICP备14008679号