当前位置: 首页> 娱乐> 明星 > 优秀网页设计排版_济南网站建设选聚搜网络一x_网络营销课程报告_合肥网络关键词排名

优秀网页设计排版_济南网站建设选聚搜网络一x_网络营销课程报告_合肥网络关键词排名

时间:2025/7/11 23:46:55来源:https://blog.csdn.net/2301_82023822/article/details/143129230 浏览次数:0次
优秀网页设计排版_济南网站建设选聚搜网络一x_网络营销课程报告_合肥网络关键词排名

一、智能指针

1.内存泄漏

①内存泄露的概念:

内存泄露是指程序在动态分配内存后,由于种种原因未能正确释放这些内存,导致这些内存无法被系统回收再利用。

②内存泄露的危害:

随着程序的运行,内存泄露会导致可用内存逐渐减少,最终可能导致程序性能下降、响应变慢,甚至系统崩溃。

③内存泄露的原因:

  • 在手动分配内存后,忘记释放内存。
  •  动态分配内存的指针被覆盖或丢失,导致无法释放内存。
  • 循环引用导致引用计数永久保持正值,从而无法被销毁。
  • 异常处理时可能会跳过内存释放代码,导致内存未能正确释放。

 

2.智能指针概念

C++中的智能指针用于自动管理动态分配的内存,有助于减少内存泄漏和其他资源管理错误。

①原理:

智能指针是一类对象,其类模板本质上是对原始指针的封装,通过重载运算符来模拟原始指针的行为。

当智能指针过期时,其析构函数负责释放内存。

智能指针通过RAII(资源获取即初始化)原则,确保了动态分配的内存在智能指针的生命周期结束时自动释放。

②种类:

智能指针包括unique_ptr、shared_ptr和weak_ptr。

ps:智能指针的头文件是<memory>。

3.unique_ptr

unique_ptr是独占所有权的智能指针,即同一时间只能有一个unique_ptr指向给定的内存块。当unique_ptr被销毁时,它所管理的内存也会被释放。

①语法:

创建unique_ptr:

unique_ptr<int> ptr1(new int(10));
unique_ptr<double> ptr2 = make_unique<double>(5.5);
cout << *ptr1 << endl;  //10
cout << *ptr2 << endl;  //5.5

get方法用于获取指向其管理的对象的原始指针,这个指针可以用来访问unique_ptr管理的对象。然而,一旦unique_ptr被重置,原始指针就无效了,此时通过它访问对象将是危险的行为。

unique_ptr<int> ptr1 = make_unique<int>(10);
int* x = ptr1.get();
cout << *x << endl;  //10
ptr1.reset();
//cout << *x << endl;  //错误

reset方法用于释放unique_ptr当前管理的对象,并可以选择性地赋予新的对象。如果不提供参数,reset会将指针设置为nullptr,并释放原有的对象。如果提供了一个新的原始指针,reset会接管这个新对象的所有权并释放旧对象。

unique_ptr<int> ptr1 = make_unique<int>(10);
cout << ptr1 << endl;
ptr1.reset(new int(20));
cout << ptr1 << endl;
//输出
0000016F516C6D10
0000016F516C6E50

release方法用于放弃unique_ptr对其管理对象的所有权,并返回一个原始指针,但没有释放内存。调用release后,unique_ptr不再拥有对象并被设置为nullptr。返回的原始指针的生命周期管理完全由我们负责,如果不正确管理,可能会导致内存泄漏。

unique_ptr<int> ptr1 = make_unique<int>(10);
cout << *ptr1 << endl;  //10
int* p = ptr1.release();
cout << *p << endl;  //10
delete p;

②所有权转移:

unique_ptr不允许复制,只能通过移动语义来转移所有权。

在所有权转移后,原先的unique_ptr将不再拥有对象的所有权,而是变为空指针。

unique_ptr<int> ptr1 = make_unique<int>(10);
//unique_ptr<int> ptr2 = ptr1;  //错误
unique_ptr<int> ptr2 = move(ptr1);
if (ptr1 == nullptr)cout << "ptr1 nullptr" << endl;
cout << *ptr2 << endl;
//输出
ptr1 nullptr
10

③作为函数参数:

当unique_ptr作为函数参数时,为了遵守其不允许拷贝的特性,通常会通过引用传递。

void func(unique_ptr<int>& ptr) {cout << *ptr << endl;
}
unique_ptr<int> ptr1 = make_unique<int>(10);
func(ptr1);
//输出10

使用const引用传递时,不能修改智能指针的指向,但能修改其指向的值。

void func(const unique_ptr<int>& ptr) {*ptr = 20;
}
unique_ptr<int> ptr1 = make_unique<int>(10);
func(ptr1);
cout << *ptr1 << endl;  //20

④作为函数返回值:

如果函数使用new分配内存,并返回指向该内存的指针,可以将其返回类型声明为unique_ptr。当unique_ptr作为返回值时,编译器会自动应用移动语义,从而高效地将所有权将转让给接受返回值的unique_ptr。

unique_ptr<int> func() {return make_unique<int>(20);
}
unique_ptr<int> ptr1 = func();
cout << *ptr1 << endl;  //20

 

4.shared_ptr

shared_ptr是共享所有权的智能指针,多个shared_ptr可以指向同一内存块,并共享所有权。当最后一个shared_ptr被销毁时,内存才会被释放。

shared_ptr共同维护一个引用计数,当一个新的shared_ptr指向原有对象时,引用计数加1;一个shared_ptr被销毁时,引用计数减1。引用计数为零时,释放所管理的对象。

①语法:

创建shared_ptr:

shared_ptr<int> ptr1 = make_shared<int>(10);
shared_ptr<double> ptr2(new double(5.5));
cout << *ptr1 << endl;  //10
cout << *ptr2 << endl;  //5.5

使用use_count方法可以查询当前有多少个shared_ptr实例共享同一个对象,复制shared_ptr会增加引用计数。

shared_ptr<int> ptr1 = make_shared<int>(10);
shared_ptr<int> ptr2 = ptr1;
cout << *ptr1 << endl;  //10
cout << *ptr2 << endl;  //10
cout << ptr1.use_count() << endl;  //2

使用move可以将其后面的shared_ptr对象的所有权转移到另一个shared_ptr对象,转移的shared_ptr的引用计数减少,且变成空指针。

shared_ptr<int> ptr1 = make_shared<int>(10);
shared_ptr<int> ptr2 = ptr1;
shared_ptr<int> ptr3 = make_shared<int>(20);
ptr1 = move(ptr3);
cout << ptr1.use_count() << endl;  //3

使用get方法可以获取指向其管理对象的原始指针。

reset方法可以改变shared_ptr所管理的对象。如果传递一个新的原始指针,reset方法会接管该指针的所有权,此时引用计数会被设置为1。如果不提供任何参数,reset方法会释放当前管理的对象,并将shared_ptr置为nullptr。

shared_ptr<int> ptr1 = make_shared<int>(10);
shared_ptr<int> ptr2 = ptr1;int* p = ptr1.get();
ptr1.reset();
cout << *p << endl;  //10
cout << ptr2.use_count() << endl;  //1ptr1.reset(new int(20));
cout << *ptr1 << endl;  //20
cout << ptr1.use_count() << endl;  //1

swap方法用于交换两个shared_ptr对象所管理的资源,这个方法在需要快速交换两个对象的所有权时非常有用。swap方法确保交换操作后,每个shared_ptr都有正确的引用计数,并且管理着正确的对象。

shared_ptr<int> ptr1 = make_shared<int>(10);
shared_ptr<int> ptr2 = ptr1;
shared_ptr<int> ptr3 = make_shared<int>(20);
ptr1.swap(ptr3);
cout << *ptr1 << endl;  //20
cout << *ptr2 << endl;  //10
cout << *ptr3 << endl;  //10
cout << ptr1.use_count() << endl;  //1
cout << ptr2.use_count() << endl;  //2
cout << ptr3.use_count() << endl;  //2

②智能指针转换:

 unique_ptr对象作右值时可以赋值给shared_ptr对象,通过move()。

unique_ptr<int> ptr1 = make_unique<int>(10);
shared_ptr<int> ptr2 = move(ptr1);cout << *ptr2 << endl;  //10
cout << ptr2.use_count() << endl;  //1

首先创建一个unique_ptr对象ptr1并初始化,然后使用move()将ptr1的所有权转移给ptr2。此时ptr1不再拥有对象的所有权,shared_ptr对象ptr2开始管理这个对象。

③作为函数参数:

在函数中用shared_ptr作为参数时有两种传递方式:按值传递和按引用传递。

按引用传递不会改变引用计数;按值传递在生成副本时引用计数会加1,在函数执行完毕后引用计数会减1。按值传递可以在函数中修改原对象,因为传递的shared_ptr对象和原本的对象指向同一块内存。

void func(const shared_ptr<int> ptr) {*ptr = 20;cout << ptr.use_count() << endl;  //2
}
shared_ptr<int> ptr1 = make_shared<int>(10);
func(ptr1);
cout << *ptr1 << endl;  //20
cout << ptr1.use_count() << endl;  //1

②不能用一个原始指针初始化多个shared_ptr:

int* p = new int(10);
//shared_ptr<int> ptr1(p);
//shared_ptr<int> ptr2(p);

原因在于,每个shared_ptr对象都认为自己在单独管理这个资源,它们会各自维护自己的引用计数,在释放内存时会造成二次析构。

⑤循环引用:

循环引用通指的是两个或多个对象相互持有对方的引用,导致它们的引用计数永远不会降为零,从而无法被自动释放。

在使用shared_ptr时可能会出现循环引用问题,例如当两个类互相持有对方的shared_ptr时,就会形成循环引用:

class Son;class Father {
public:shared_ptr<Son> m_son;~Father() {cout << "~Father()" << endl;}
};class Son {
public:shared_ptr<Father> m_father;~Son() {cout << "~Son()" << endl;}
};
void test01() {shared_ptr<Father> father = make_shared<Father>();shared_ptr<Son> son = make_shared<Son>();son->m_father = father;father->m_son = son;
}//没有输出

Father类和Son类通过shared_ptr相互持有对方的指针,形成了一个循环引用。

使用make_shared创建father对象和son对象时,它们的引用计数均为1。father对象包含的m_son成员指向son对象,使得son对象的引用计数为2;同时,son对象包含的m_father成员指向father对象,使得father对象的引用计数也为2。

在作用域结束后,son指针被销毁,此时son对象的引用计数是1;father指针被销毁,此时father对象的引用计数也是1。它们通过循环引用维持着对方的引用计数,这导致father和son对象仍然存在,所以它们在作用域结束后不会被自动销毁,导致内存泄漏。

为了解决循环引用问题,可以使用weak_ptr。

5.weak_ptr

作为shared_ptr的补充,weak_ptr不会增加所指向对象的引用计数,主要用于解决shared_ptr循环引用的问题。

weak_ptr不支持使用->运算符和解引用,它提供了一种不参与对象引用计数的弱引用。

①解决循环引用问题:

在上述代码中,只需要将Father类或Son类中的shared_ptr改为weak_ptr就可以解决问题。

class Son;class Father {
public:weak_ptr<Son> m_son;~Father() {cout << "~Father()" << endl;}
};class Son {
public:shared_ptr<Father> m_father;~Son() {cout << "~Son()" << endl;}
};
void test01() {shared_ptr<Father> father = make_shared<Father>();shared_ptr<Son> son = make_shared<Son>();son->m_father = father;father->m_son = son;
}//输出
~Son()
~Father()

起初,father对象的引用计数是2,而son对象的引用计数是1。

作用域结束后,son指针被销毁使得son对象的引用计数变为0,son对象会被析构,导致son对象包含的m_father指针被销毁,使得father对象的引用计数变为1,然后father指针被销毁使得father对象的引用计数变为0,所以father对象也会被析构。

②转换与调用:

weak_ptr只能从shared_ptr或另一个weak_ptr构造,且不能直接访问所引用的对象。可以使用lock方法将weak_ptr提升为shared_ptr。

lock方法会尝试返回一个指向其管理对象的shared_ptr。如果weak_ptr指向的对象仍然存在,lock方法将返回一个有效的shared_ptr;如果对象已经被销毁,则会返回一个空的shared_ptr。

shared_ptr<int> ptr1 = make_shared<int>(10);
weak_ptr<int> ptr2 = ptr1;
//*ptr2 = 20;  //错误shared_ptr<int> ptr3 = ptr2.lock();
if (ptr3!=nullptr)cout << "yes" << endl;  //yes*ptr3 = 20;
cout << *ptr3 << endl;  //20
cout << ptr2.use_count() << endl;  //2

通过lock方法获取shared_ptr后,weak_ptr自身的状态并没有改变,仍然保持其弱引用的功能。

 

 

 

 

 

关键字:优秀网页设计排版_济南网站建设选聚搜网络一x_网络营销课程报告_合肥网络关键词排名

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: