智能指针是C++中用来管理动态内存的一种机制。它通过对指针对象进行封装,使得在特定的作49·47用域内自动管理内存的分配和释放。
智能指针的主要用途是解决C++中常见的内存泄漏和空悬指针问题。它提供了一种方便而安全地使用动态分配对象的方法。
在C++中,有三种智能指针类型:std::shared_ptr、std::unique_ptr和std::weak_ptr。
std::shared_ptr:是一种共享所有权的智能指针。它可以多个指针同时拥有同一个对象,对象只有在最后一个拥有者释放时才会被销毁。这种指针可以通过std::make_shared函数来创建,也可以使用new关键字来创建。
std::unique_ptr:是一种独占所有权的智能指针。只能有一个unique_ptr
指向某个对象。当unique_ptr
销毁时,其所指向的对象也会被自动删除。这种指针可以使用new关键字来创建,也可以通过std::make_unique函数来创建
std::weak_ptr:不拥有对象的所有权,只是对shared_ptr
的一个引用。它可以用来检测对象是否已被删除,并避免循环引用。
新建一个Pointers类来举例说明,类定义如下:
#include<memory>
class Pointers {
public:
Pointers()=default;
Pointers(std::string name):name(name){
std::cout << "Pointers is constructor:" <<name<< std::endl;
}
~Pointers() {
std::cout << "Pointers is destroy:" <<name<< std::endl;
}
void info()const {
std::cout << "Pointers name:" << name<<std::endl;
}
std::string getName()const {
return name;
}
void setName(const std::string& name) {
this->name = name;
}
void setSName(std::shared_ptr<Pointers> c) {
w_ptr_p= c;
}
private:
std::string name{"First"}; // std::string name = { "First" };
std::weak_ptr<Pointers> w_ptr_p;
};
/*智能指针第一种创建方法*/
Pointers* p = new Pointers("A");
std::unique_ptr<Pointers>u_c_p{ p };
p = nullptr;
/*智能指针第二种创建方法*/
std::unique_ptr<Pointers>u_c_p1(new Pointers("B")); //隐式创建类
/*智能指针第三中创建方法*/
std::unique_ptr<Pointers>u_c_p2 = std::make_unique<Pointers>();
? ? ? ? 该方法用于释放智能指针所指向的资源。当调用?reset
?方法时,智能指针会将其内部的计数器减一,如果计数器减至零,则会自动释放其所指向的资源。
????? 这个函数用于将?unique_ptr
?的所有权转移给另一个?unique_ptr
。当一个?unique_ptr
?调用?move()
?函数后,它就会变成一个空指针,而所有权则转移给了另一个?unique_ptr
。
void uniq_ptr_pass_value(std::unique_ptr<Pointers> ptr) {
ptr->setName("value");
std::cout << "通过move传递,原始智能指针失效:" << ptr->getName() << std::endl;
}
int maint(){
std::unique_ptr<Pointers> pt = std::make_unique<Pointers>("pt");
uniq_ptr_pass_value(move(pt));
uniq_ptr_pass_value(std::make_unique<Pointers>()); //相当于调用了move
pt->->info(); //报错, 通过move传递后,pt变成空指针
}
unique_ptr<Pointers> c_p = make_unique<Pointers>("yy");
shared_ptr<Pointers>s_p = move(c_p);
? ? ? ? 因为unique_ptr不能复制, 所以除了move(),还可以引用的方式作为函数参数。此时需要注意有const和没有const的情况。
void uniq_ptr_ref(std::unique_ptr<Pointers>& ptr) {
ptr.reset(); //没有加const时可以调用reset();
}
void uniq_ptr_refconst(const std::unique_ptr<Pointers>& ptr) {
ptr.reset(); //有const限定符时会报错,
}
int main(){
std::unique_ptr<Pointers> c_p_1 =std::make_unique<Pointers>("aa");
uniq_ptr_ref(c_p_1); //此函数会释放c_p_1指向的资源并把指针c_p_1置为空
c_p_1->info(); //报错,c_p_1为空。
std::unique_ptr<Pointers> c_p_2 =std::make_unique<Pointers>("bb");
uniq_ptr_refconst(c_p_2);
c_p_2->info(); //正常输出
}
? ? 该函数返回指向由?shared_ptr
?管理的对象的共享所有权的引用计数。
shared_ptr<Pointers> c_p_1 = make_shared<Pointers>();
shared_ptr<Pointers> c_p_2 = c_p_1;
shared_ptr<Pointers> c_p_3{ c_p_2 };
cout << "c_p_1 use_count: " << c_p_1.use_count() << endl; //输出3
cout << "c_p_2 use_count: " << c_p_2.use_count() << endl; //输出3
cout << "c_p_3 use_count: " << c_p_3.use_count() << endl; //输出3
void shared_ptr_value(shared_ptr<Pointers> ptr) {
cout << "func use_count: " << ptr.use_count() << endl;
}
void shared_ptr_ref(shared_ptr<Pointers>& ptr) {
cout << "func use_count: " << ptr.use_count() << endl;
}
void shared_ptr_ref_const(const shared_ptr<Pointers>& ptr) {
cout << "func use_count: " << ptr.use_count() << endl;
//ptr.reset(); //这里不能被reset,因为有const限制
}
int main(){
std::shared_ptr<Pointers> c_p_1=std::make_shared<Pointers>("cc");
shared_ptr_value(c_p_1); //输出2
std::cout<<c_p_1.use_count()<<std::endl; //输出1
shared_ptr_ref(c_p_1); //输出1
shared_ptr_ref_const(c_p_1); //输出1
}
? ? ? ? weak_ptr指针不能直接创建,通过指向shared_ptr得到weak_ptr指针。
shared_ptr<Pointers>s_ptr_p1 = make_shared<Pointers>("ff");
weak_ptr<Pointers>w_ptr_p1{ s_ptr_p1 }; //得到一个weak_ptr指针
std::cout<<s_ptr_p1.use_count()<<std::endl; //输出1,weak_ptr不会增加shared_ptr的计数
????????lock()
?函数的主要用途是尝试获取对对象的访问权。如果?std::weak_ptr
?所指向的对象仍然存在,那么?lock()
?函数将返回一个指向该对象的?std::shared_ptr
,并且该?std::shared_ptr
?的引用计数加一。如果对象不存在,那么?lock()
?函数将返回一个空的?std::shared_ptr
。
shared_ptr<Pointers>s_ptr_p = make_shared<Pointers>("hh");
shared_ptr<Pointers>s_ptr_p1(new Pointers("gg"));
weak_ptr<Pointers>w_ptr_p = s_ptr_p; //weak_ptr指向s_ptr_p
s_ptr_p1 = w_ptr_p.lock(); //如果w_ptr_p指向的对象存在,lock()函数返回有效的std::shared_ptr,并让s_ptr_p1的引用计数器加1,如果不存在就返回空的std::shared_ptr
if(s_ptr_p1){
// 对象仍然存在,可以安全地使用它
std::cout << s_ptr_p1.use_count()<<std::endl; //输出2
} else {
// 对象已经被删除,不能使用它
std::cout << "sptr2 points to an invalid object\n";
}
????????在使用?std::shared_ptr
?时没有正确地管理共享所有权,可能会导致死循环问题。死循环问题通常发生在两个或多个?shared_ptr
?对象相互引用时,导致它们之间的引用计数永远不会减少到零,从而导致程序无法正常结束。
#include<iostream>
#include<memory>
class Pointers {
public:
Pointers()=default;
Pointers(std::string name):name(name){
std::cout << "Pointers is constructor:" <<name<< std::endl;
}
~Pointers() {
std::cout << "Pointers is destroy:" <<name<< std::endl;
}
void setName(std::shared_ptr<Pointers> c) {
m_sptr= c;
//m_wptr=c;
}
private:
std::string name{"First"}; // std::string name = { "First" };
//std::weak_ptr<Pointers> m_wptr;
std::shared_ptr<Pointers> m_sptr;
};
int main(){
std::shared_ptr<Pointers> s_ptr_p= std::make_shared<Pointers>("jj");
std::shared_ptr<Pointers> s_ptr_p1= std::make_shared<Pointers>("kk");
//创建了两个shared_ptr<Pointers>
s_ptr_p->setName(s_ptr_p1);
s_ptr_p1->setName(s_ptr_p);
//两个shared_ptr对象相互引用, 此时程序会进入死循环,永远不能释放这两个指针
//此时,可用weak_ptr指针来避免死循环。把Pointers类的成员变量-shared_ptr换成weak_ptr就可以了
}