C++超详细讲解智能指针
简介
在C++中,智能指针是一种非常有用、安全的内存管理工具。相较于原始指针,它能够自动释放内存,避免内存泄漏等问题。同时,智能指针也能够避免重复释放内存、访问空指针以及释放栈上分配的内存等问题。本文将对智能指针进行详细的讲解,介绍其类型、使用方法以及注意事项。
智能指针类型
在C++中,常见的智能指针有以下几种:
unique_ptr
unique_ptr是C++11引入的一种独占式智能指针。它能够自动管理动态分配的内存,并在不需要时自动释放。
示例:
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int> p(new int(42));
std::cout << *p << std::endl;
return 0;
}
在以上示例中,定义了一个unique_ptr指针p,并通过new运算符分配了一个整型变量的内存空间,该指针p独占该内存空间,当p超出作用域时,该内存空间会自动被释放。
shared_ptr
shared_ptr是一种共享式智能指针,它允许多个智能指针同时指向同一个对象,并会自动释放对象的内存空间,当最后一个指向该对象的智能指针被销毁时。
示例:
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> p1(new int(42));
std::shared_ptr<int> p2 = p1;
std::cout << *p1 << std::endl;
std::cout << *p2 << std::endl;
return 0;
}
在以上示例中,定义了两个shared_ptr指针,通过将p1赋值给p2,两个指针共享同一个对象的内存空间,当p1和p2超出作用域时,该内存空间会自动被释放。
weak_ptr
weak_ptr是一种弱引用智能指针,它指向一个shared_ptr所管理的对象,但它并不对所指的对象进行引用计数,而只是提供了一个观察的手段。当最后一个shared_ptr被销毁时,weak_ptr自动失效。
示例:
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> p1(new int(42));
std::weak_ptr<int> p2 = p1;
std::cout << *p1 << std::endl;
// std::cout << *p2 << std::endl; // weak_ptr不能直接使用,需要先判断是否过期
if (auto p3 = p2.lock()) {
std::cout << *p3 << std::endl;
}
return 0;
}
在以上示例中,定义了一个shared_ptr指针p1和一个weak_ptr指针p2,通过将p1赋值给p2,p2指向p1所管理的对象,在输出p1的值之后,使用weak_ptr的lock()方法获取p2指向的对象,并输出该对象的值。
智能指针使用方法
定义智能指针
定义智能指针可以使用STL中的模板类unique_ptr、shared_ptr和weak_ptr,以及boost库中的intrusive_ptr、scoped_ptr等。
#include <memory>
#include <boost/scoped_ptr.hpp>
int main(){
std::shared_ptr<int> p1(new int(1));
std::unique_ptr<int> p2(new int(2));
boost::scoped_ptr<int> p3(new int(3));
return 0;
}
释放内存空间
不需要手动释放。当智能指针超出其作用域后,其指向的内存空间会自动被回收。
获取指针的指向
对于unique_ptr和shared_ptr,可以使用get()方法获取底层的原始指针;对于weak_ptr,需要使用其lock()方法获取底层的shared_ptr指针,然后再使用get()方法获取底层的原始指针。
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int> p1(new int(1));
std::shared_ptr<int> p2(new int(2));
std::weak_ptr<int> p3 = p2;
std::cout << p1.get() << std::endl; // 输出p1指向的原始指针地址
std::cout << p2.get() << std::endl; // 输出p2指向的原始指针地址
std::cout << p3.lock().get() << std::endl; // 输出p3指向的原始指针地址
return 0;
}
其他操作
可以通过reset()方法将智能指针重置为nullptr;使用operator bool()方法检查智能指针是否为空指针。
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int> p1(new int(1));
std::shared_ptr<int> p2(new int(2));
p1.reset(); // 释放p1
p2.reset(); // 释放p2
std::cout << p1 << std::endl; // 输出nullptr
std::cout << p2 << std::endl; // 输出nullptr
if (!p1) {
std::cout << "p1 is null" << std::endl; //输出p1为空指针
}
if (!p2) {
std::cout << "p2 is null" << std::endl; //输出p2为空指针
}
return 0;
}
注意事项
避免循环引用
当两个对象互相引用时,可能会导致内存泄漏。比如,一个对象A持有另一个对象B的shared_ptr,而B对象也持有A对象的shared_ptr。这种情况下,两个A、B对象的引用计数永远不会变为0,导致泄漏内存。
要避免这种循环引用,可以使用weak_ptr。一般情况下,A对象持有B对象的shared_ptr,而B对象持有A对象的weak_ptr。
不允许栈上分配
由于智能指针的析构函数是自动释放分配的堆栈内存,因此不允许在栈上分配智能指针。
std::unique_ptr<MyClass> p(new MyClass); // 正确写法
std::unique_ptr<MyClass> p2 = std::make_unique<MyClass>(); // C++14后的写法
std::unique_ptr<MyClass> p3(&myclass); // 错误写法,不能在栈上分配
总结
本文对C++中的智能指针进行了介绍,包括其类型、使用方法以及注意事项。智能指针是一种非常有用、安全的内存管理工具,使用智能指针可以避免很多内存管理问题。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++超详细讲解智能指针 - Python技术站