auto_ptr智能指针
- 格式:doc
- 大小:43.00 KB
- 文档页数:4
1>为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源.如下:void Func(){Investment* pInv = createInvestment();//createInvestment是工厂方法.返回一个堆上的对象指针...;delete pInv;}这时当在...区域一个过早的return,continue,goto语句退出.这样在区域内的语句抛出异常,这样delete就被忽略过去,这时就发生了内存泄漏,我们泄漏的不只是内含对象的那块内存,还包括那些对象所保存的任何资源.*为确保createInvestment返回的资源总是被释放,我们需要将资源放进对象内,当控制流离开了Func(),该对象的析构函数会自动释放那些资源.这就是把资源放进对象内.如下:void Func(){std::auto_ptr<Invesment> pInv(createInvestment()); //auto_ptr"以对象管理资源"}2>两个常被使用的RAII classes分别是tr1::shared_ptr和auto_ptr.前者是较好的选择,由于auto_ptr被销毁时会自动删除它所指之物,所以一定要注意别让多个auto_ptr同时指向同一个对象,若通过copy构造函数或copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权.如下:void Func1(){std::auto_ptr<Investment> pInv1(createInvestment());//pInv1指向工厂函数createInvestment返回物std::auto_ptr<Investment> pInv2(pInv1); //现在pInv2指向上述对象,但pInv1被设为null了pInv1 = pInv2; //现在pInv1指向上述对象了.pInv2被设为null了}但tr1::shared_ptr却可以保证多个对象指向同一笔资源,并在无人指向它时自动删除该资源.如下void Func1(){std::tr1::shared_ptr<Investment> pInv1(createInvestment());//pInv1指向crateInvestment返回物std::tr1::shared_ptr<Investment> pInv2(pInv1); //pInv1和pInv2指向同一个对象pInv1 = pInv2; //同上,无任何改变}//函数结束后,pInv1和pInv2被销毁,它们所指的对象也被自动销毁*auto_ptr在头文件<memory>中*shared_ptr在boost的头文件模块中.在vs最新的编译器己可用.但在vc6上却找不到该模块.注:本文转自/s/blog_5fa144950100knsz.html#因为auto_ptr并不是完美无缺的,它的确很方便,但也有缺陷,在使用时要注意避免。
一、Introduction在进行C++编程时,经常会遇到需要找出各个类型的最大数的情景。
C++11引入了一些新的类型和函数,使得查找各个类型的最大数变得更加方便和高效。
本文将对C++11中各个类型的最大数函数进行详细介绍。
二、Integral types(整数类型)1.对于8位有符号整数(int8_t)和无符号整数(uint8_t),可以使用numeric_limits来获取最大值。
2.对于16位整数(int16_t)和无符号整数(uint16_t),也可以使用numeric_limits来获取最大值。
3.对于32位整数(int32_t)和无符号整数(uint32_t),同样可以使用numeric_limits来获取最大值。
4.对于64位整数(int64_t)和无符号整数(uint64_t),同样可以使用numeric_limits来获取最大值。
5.对于long类型,可以使用LONG_MAX来获取最大值。
三、Floating-point types(浮点数类型)1.对于float类型,可以使用FLT_MAX来获取最大值。
2.对于double类型,可以使用DBL_MAX来获取最大值。
3.对于long double类型,可以使用LDBL_MAX来获取最大值。
四、Other types(其他类型)1.对于指针类型,可以使用PTRDIFF_MAX来获取最大值。
2.对于布尔类型,最大值为true。
3.对于字符类型,最大值为127(对于有符号字符)或255(对于无符号字符)。
五、Conclusion通过C++11中新增加的类型和函数,我们可以更加方便地获取各种类型的最大数。
这些新的特性使得C++编程更加高效和便捷。
在实际编程中,我们可以根据具体的需求选择合适的类型和函数来获取最大数,从而提高程序的性能和可读性。
希望本文对大家有所帮助。
C++11中关于各个数据类型最大数函数的介绍仅仅是C++11引入的一系列新特性之一。
【原】C++ 11智能指针之shared_ptrshared_ptr是一个引用计数智能指针,用于共享对象的所有权。
它可以从一个裸指针、另一个shared_ptr、一个auto_ptr、或者一个weak_ptr构造。
还可以传递第二个参数给shared_ptr的构造函数,它被称为删除器(deleter)。
删除器用于处理共享资源的释放,这对于管理那些不是用new分配也不是用delete释放的资源时非常有用。
shared_ptr 被创建后,就可以像普通指针一样使用了,除了一点,它不能被显式地删除。
shared_ptr的比较重要的接口如下:template <class T>explicit shared_ptr(T* p);这个构造函数获得给定指针p的所有权。
参数p必须是指向T的有效指针。
构造后引用计数设为1。
唯一从这个构造函数抛出的异常是std::bad_alloc(仅在一种很罕见的情况下发生,即不能获得引用计数器所需的空间)。
template <class T,class D>shared_ptr(T* p,D d);这个构造函数带有两个参数。
第一个是shared_ptr将要获得所有权的那个资源,第二个是shared_ptr被销毁时负责释放资源的一个对象,被保存的资源将以d(p)的形式传给那个对象。
如果引用计数器不能分配成功,shared_ptr 抛出一个类型为std::bad_alloc的异常。
shared_ptr(const shared_ptr& r);r中保存的资源被新构造的shared_ptr所共享,引用计数加一。
这个构造函数不会抛出异常。
template <class T>explicit shared_ptr(const weak_ptr<T>& r);从一个weak_ptr构造shared_ptr。
这使得weak_ptr的使用具有线程安全性,因为指向weak_ptr参数的共享资源的引用计数将会自增(weak_ptr不影响共享资源的引用计数)。
Boost使用笔记(Smart_ptr)概述Boost库是一个功能强大、构造精巧、跨平台、开源免费的C++程序库,提供了代码编写中所需要的几乎所有常见工具,例如智能指针、bind、正则表达式、xml解析等工具。
其代码以泛型编程为基础,且绝大部分代码放在扩展名为hpp的头文件中,以内联的方式引入到目标程序,因此Boost库几乎无需编译即可使用。
最新版的C++标准中已经将boost部分模块纳入其中,足见其功能的强大。
目前Boost库是除STL库以外最常用的C++代码库之一。
在实际开发中,Boost多用于应用软件和游戏编程,由于代码量相当庞大,且内部各模块互相引用牵连,致使使用Boost中很小的功能,也要将整个Boost库全部安装,应用上相对冗余,不过由于Boost以泛型编程为基础,实际编译到目标程序中的代码量并不大,且多为Inline形式,效率上也同样不差。
Boost是跨平台的,其代码支持Win、Linux、Vxworks等平台,由于精力和时间有限没有对完整的库在Vxworks下进行验证,经过试验的库有3个:●smart_ptr●xpressive●property_tree三个库在Vxworks6.4及Vxworks6.8上都做过实验,并且在板卡上试验了Boost的兼容性及性能。
在实验中smart_ptr库在Vxworks6.4及Vxworks6.8平台下均可编译执行,由于smart_ptr模块相对其他模块较为独立,现已将其从Boost库中全部抽取出来(大概218个文件)上传到Git中,可以在编码中独立使用。
https:///guolisen/BoostSmartPtr.git 需要注意的是BoostSmartPtr由Boost 1.43.0代码而来,目前只支持shared_ptr。
前面介绍过boost库代码互相牵连,即使加入一个weak_ptr也需要再加入关联的好几百个文件,因此为保证精简性没有将其加入。
1 auto_ptr的意义auto_ptr是一种智能指针,当系统异常退出的时候避免资源泄漏(内存)。
其他的资源还对应其他的智能指针。
2 auto_ptr的使用std::auto_ptr<int> test(new int(1));test将是一个auto_ptr的对象,使用一个int指针进行初始化。
test可以象其他指针一样使用,如使用* 使用->但是++不可以使用,以后也许会扩展,其实难对++做越界管理,也许可以放弃一些速度。
当使用auto_ptr的时候,必须使用显式的类型转化来初始化,如auto_ptr<classA> a(new classA)而不能使用auto_ptr<classA> a = new classA;3 auto_ptr所有权的转移auto_ptr对所有权有严格的约定,一个auto_ptr只能控制一个指针,不能控制多个,当auto_ptr拥有一个指针的时候就不能在拥有其他的指针了。
同时,不同的auto_ptr不能拥有同一个指针。
但是存在这样的情况,不同的auto_ptr可能控制着相同的对象,不要出现这样的情况。
auto_ptr<int> a(new int); 1auto_ptr<int> b(a); 2auto_ptr<int> c = b; 3auto_ptr<int> d(int); 4d =c;5当2发生的时候,a将所有权放弃,b获得所有权。
当3发生时,b将放弃所有权,c获得所有权当5发生时,c的所有权给d,d将释放自己的所有权,并把对象删除掉。
4 来源和接收当auto_ptr以参数的形式传递给函数的时候,作用域同样发生了变化,从之前的作用域变成了函数内部的作用域。
过程时这样的,当有auto_ptr作为参数传递到函数内部的时候,首先会交接自己的所有权,所有权交给了函数的参数,作用域编程了函数的内部。
C++智能指针试题1.auto_ptr在C++11中被标记为已弃用,主要因为它具有哪个性质导致资源管理混乱?o A. 所有权转移时的浅拷贝o B. 可以显式释放资源o C. 强制类型转换的构造函数o D. 没有引用计数答案: A解析: auto_ptr在拷贝构造和赋值操作时,仅进行所有权转让,而不是深拷贝,这可能导致原对象的资源被释放后,新对象仍试图使用已被释放的资源,造成悬挂指针。
2.假设有一个unique_ptr对象uptr,以下哪个操作是非法的?o A. uptr->func();o B. (*uptr).func();o C. uptr = nullptr;o D. uptr = uptr;答案: D解析: unique_ptr不允许自我赋值,因为这会导致资源管理混乱,即两次释放相同的资源。
3.shared_ptr的主要优势是什么?o A. 自动管理资源的生命周期o B. 所有权的唯一性o C. 可以在不同线程间安全地传递o D. 消耗的资源比auto_ptr和unique_ptr少答案: A解析: shared_ptr通过引用计数管理资源的生命周期,当引用计数为0时自动释放资源,从而允许多个shared_ptr实例共享相同的资源。
4.以下哪项描述了unique_ptr和shared_ptr之间的一个关键区别?o A. unique_ptr可以使用new[]分配的数组o B. shared_ptr可以被复制和转移o C. unique_ptr支持任意类型o D. shared_ptr的析构函数是公有的答案: B解析: unique_ptr不支持复制和转移所有权,而shared_ptr通过引用计数机制支持复制和所有权的共享。
5.在以下代码片段中,ptr指向的对象何时被销毁?o B. 当weakPtr离开作用域时o C. 当ptr引用计数变为0时o D. 代码编译错误,无法执行答案: C解析: shared_ptr在引用计数为0时会释放资源,当ptr被赋值为weakPtr (实质上是一个shared_ptr)时,原ptr指向的对象的引用计数变为0。
C++中shared_ptr循环引⽤计数问题转⾃c++智能指针介绍由于 C++ 语⾔没有⾃动内存回收机制,程序员每次 new 出来的内存都要⼿动 delete,⽐如流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执⾏ delete 的情况并不罕见,并造成内存泄露。
如此c++引⼊,智能指针即是C++ RAII的⼀种应⽤,可⽤于动态资源管理,资源即对象的管理策略。
智能指针在 <memory> 标头⽂件的 std 命名空间中定义。
它们对 RAII 或获取资源即初始化编程惯⽤法⾄关重要。
RAII 的主要原则是为所有堆分配资源提供所有权,例如动态分配内存或系统对象句柄、析构函数包含要删除或释放资源的代码的堆栈分配对象,以及任何相关清理代码。
c++智能指针类别c++ 智能指针主要包括:unique_ptr,shared_ptr, weak_ptr, 这三种,其中auto_ptr 已被遗弃。
unique_ptr只允许基础指针的⼀个所有者。
可以移到新所有者(具有移动语义),但不会复制或共享(即我们⽆法得到指向同⼀个对象的两个unique_ptr)。
替换已弃⽤的 auto_ptr。
相较于 boost::scoped_ptr。
unique_ptr ⼩巧⾼效;⼤⼩等同于⼀个指针,⽀持 rvalue 引⽤,从⽽可实现快速插⼊和对 STL 集合的检索。
头⽂件:<memory>。
使⽤unique_ptr,可以实现以下功能:1、为动态申请的内存提供异常安全。
2、将动态申请内存的所有权传递给某个函数。
3、从某个函数返回动态申请内存的所有权。
4、在容器中保存指针。
5、所有auto_ptr应该具有的(但⽆法在C++ 03中实现的)功能。
如下代码所⽰:1. class A2. // 如果程序执⾏过程中抛出了异常,unique_ptr就会释放它所指向的对象3. // 传统的new 则不⾏4. unique_ptr5.6. unique_ptr p(new A)7. //do something8. return9.10.11. void fun2()12. // unique_ptr具有移动语义13. unique_ptr// 使⽤移动构造函数14. // do something15. // 在函数退出的时候,p以及它所指向的对象都被删除释放shared_ptr采⽤引⽤计数的智能指针。
C++智能指针shared_ptrC++智能指针 shared_ptr shared_ptr 是⼀个标准的共享所有权的智能指针, 允许多个指针指向同⼀个对象. 定义在 memory ⽂件中(⾮memory.h), 命名空间为 std. shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的), 在使⽤引⽤计数的机制上提供了可以共享所有权的智能指针, 当然这需要额外的开销: (1) shared_ptr 对象除了包括⼀个所拥有对象的指针外, 还必须包括⼀个引⽤计数代理对象的指针. (2) 时间上的开销主要在初始化和拷贝操作上, *和->操作符重载的开销跟auto_ptr是⼀样. (3) 开销并不是我们不使⽤shared_ptr的理由, 永远不要进⾏不成熟的优化, 直到性能分析器告诉你这⼀点. 使⽤⽅法:可以使⽤模板函数 make_shared 创建对象, make_shared 需指定类型('<>'中)及参数('()'内), 传递的参数必须与指定的类型的构造函数匹配. 如: std::shared_ptr<int> sp1 = std::make_shared<int>(10); std::shared_ptr<std::string> sp2 = std::make_shared<std::string>("Hello c++");也可以定义 auto 类型的变量来保存 make_shared 的结果. auto sp3 = std::make_shared<int>(11); printf("sp3=%d\n", *sp3); auto sp4 = std::make_shared<std::string>("C++11"); printf("sp4=%s\n", (*sp4).c_str());成员函数use_count 返回引⽤计数的个数unique 返回是否是独占所有权( use_count 为 1)swap 交换两个 shared_ptr 对象(即交换所拥有的对象)reset 放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引⽤计数的减少get 返回内部对象(指针), 由于已经重载了()⽅法, 因此和直接使⽤对象是⼀样的.如 shared_ptr<int> sp(new int(1)); sp 与 sp.get()是等价的以下代码演⽰各个函数的⽤法与特点:std::shared_ptr<int> sp0(new int(2));std::shared_ptr<int> sp1(new int(11));std::shared_ptr<int> sp2 = sp1;printf("%d\n", *sp0); // 2printf("%d\n", *sp1); // 11printf("%d\n", *sp2); // 11sp1.swap(sp0);printf("%d\n", *sp0); // 11printf("%d\n", *sp1); // 2printf("%d\n", *sp2); // 11std::shared_ptr<int> sp3(new int(22));std::shared_ptr<int> sp4 = sp3;printf("%d\n", *sp3); // 22printf("%d\n", *sp4); // 22sp3.reset();printf("%d\n", e_count()); // 0printf("%d\n", e_count()); // 1printf("%d\n", sp3); // 0printf("%d\n", sp4); // 指向所拥有对象的地址std::shared_ptr<int> sp5(new int(22));std::shared_ptr<int> sp6 = sp5;std::shared_ptr<int> sp7 = sp5;printf("%d\n", *sp5); // 22printf("%d\n", *sp6); // 22printf("%d\n", *sp7); // 22printf("%d\n", e_count()); // 3printf("%d\n", e_count()); // 3printf("%d\n", e_count()); // 3sp5.reset(new int(33));printf("%d\n", e_count()); // 1printf("%d\n", e_count()); // 2printf("%d\n", e_count()); // 2printf("%d\n", *sp5); // 33printf("%d\n", *sp6); // 22printf("%d\n", *sp7); // 22 auto r = std::make_shared<int>(); // r 的指向的对象只有⼀个引⽤, 其 use_count == 1 auto q = r; (或auto q(r);) // 给 r 赋值, 令其指向另⼀个地址, q 原来指向的对象的引⽤计数减1(如果为0, 释放内存), r指向的对象的引⽤计数加1, 此时 q 与 r 指向同⼀个对象, 并且其引⽤计数相同, 都为原来的值加1.以下⾯的代码测试:std::shared_ptr<int> sp1 = std::make_shared<int>(10);std::shared_ptr<int> sp2 = std::make_shared<int>(11);auto sp3 = sp2; 或 auto sp3(sp2);printf("e_count = %d\n", e_count()); // 1printf("e_count = %d\n", e_count()); // 2printf("e_count = %d\n", e_count()); // 2sp3 = sp1;printf("e_count = %d\n", e_count()); // 2printf("e_count = %d\n", e_count()); // 1printf("e_count = %d\n", e_count()); // 2何时需要使⽤ shared_ptr ?(1) 程序不知道⾃⼰需要使⽤多少对象. 如使⽤窗⼝类, 使⽤ shared_ptr 为了让多个对象能共享相同的底层数据.std::vector<std::string> v1; // ⼀个空的 vector// 在某个新的作⽤域中拷贝数据到 v1 中{std::vector<std::string> v2;v2.push_back("a");v2.push_back("b");v2.push_back("c");v1 = v2;} // 作⽤域结束时 v2 被销毁, 数据被拷贝到 v1 中(2) 程序不知道所需对象的准确类型.(3) 程序需要在多个对象间共享数据.⾃定义释放器(函数) ⾃定义释放器(函数), 它能完成对 shared_ptr 中保存的指针进⾏释放操作, 还能处理 shared_ptr 的内部对象未完成的部分⼯作. 假设如下是⼀个连接管理类, 此类由于历史原因, ⽆法在析构函数中进⾏断开连接, 此时⽤⾃定义的释放器可以很好的完成此⼯作: class CConnnect{void Disconnect() { PRINT_FUN(); }};void Deleter(CConnnect* obj){obj->Disconnect(); // 做其它释放或断开连接等⼯作delete obj; // 删除对象指针}std::shared_ptr<CConnnect> sps(new CConnnect, Deleter);使⽤ shared_ptr 的注意事项(1) shared_ptr 作为被保护的对象的成员时, ⼩⼼因循环引⽤造成⽆法释放资源. 假设 a 对象中含有⼀个 shared_ptr<CB> 指向 b 对象, b 对象中含有⼀个 shared_ptr<CA> 指向 a 对象, 并且 a, b 对象都是堆中分配的。
C++基础(auto_ptr作用和用法)标准auto_ptr智能指针机制很多人都知道,但很少使用它。
这真是个遗憾,因为auto_ptr 优雅地解决了C++设计和编码中常见的问题,正确地使用它可以生成健壮的代码。
本文阐述了如何正确运用auto_ptr来让你的代码更加安全——以及如何避免对auto_ptr危险但常见的误用,这些误用会引发间断性发作、难以诊断的bug。
1.为什么称它为“自动”指针? auto_ptr只是众多可能的智能指针之一。
许多商业库提供了更复杂的智能指针,用途广泛而令人惊异,从管理引用的数量到提供先进的代理服务。
可以把标准C++ auto_ptr看作智能指针的Ford Escort(elmar注:考试大提示:可能指福特的一种适合家居的车型):一个简易、通用的智能指针,它不包含所有的小技巧,不像专用的或高性能的智能指针那么奢华,但是它可以很好的完成许多普遍的工作,它很适合日常性的使用。
auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理。
这里是一个简单的代码示例,没有使用auto_ptr所以不安全:// 示例 1(a): 原始代码 //void f(){T* pt( new T );...代码...delete pt;}如果f()函数只有三行并且不会有任何意外,这么做可能挺好的。
但是如果f()从不执行delete语句,或者是由于过早的返回,或者是由于执行函数体时抛出了异常,那么这个被分配的对象就没有被删除,从而我们产生了一个经典的内存泄漏。
能让示例1(a)安全的简单办法是把指针封装在一个“智能的”类似于指针的对象里,这个对象拥有这个指针并且能在析构时自动删除这个指针所指的对象。
因为这个智能指针可以简单的当成一个自动的对象(这就是说,它出了作用域时会自动毁灭),所以很自然的把它称之为“智能”指针:// 示例 1(b): 安全代码, 使用了auto_ptr //void f(){auto_ptr pt( new T );...代码...} // 当pt出了作用域时析构函数被调用, 从而对象被自动删除现在代码不会泄漏T类型的对象,不管这个函数是正常退出还是抛出了异常,因为pt的析构函数总是会在出栈时被调用。
c++11面试知识点总结1.移动语义和右值引用:C++11引入了右值引用和移动语义,通过&&修饰,可以使得对象的值被“移动”而不是“复制”,提高性能。
2.智能指针:C++11引入了unique_ptr和shared_ptr两种智能指针,可以自动管理动态分配的内存,避免内存泄漏和悬挂指针问题。
3.多线程:C++11引入了线程库,包括线程创建、同步、互斥等功能,使得多线程编程更加方便和高效。
mbda表达式:C++11引入了lambda表达式,可以方便地定义匿名函数,简化代码,提高代码可读性。
5.数据类型增强:C++11引入了auto关键字,可以自动推导变量的类型;还增加了nullptr和enum class等用于提高代码的可靠性和可读性的特性。
6.统一初始化语法:C++11引入了统一初始化语法,即可以用“{}”来初始化对象,可以避免窄化转换和隐式类型转换的问题。
7.右值引用相关的特性:C++11引入了移动构造函数和移动赋值运算符,可以提高对象的效率;还引入了完美转发和转移语义等,使得代码更加灵活和高效。
8.并发编程:C++11在语言层面上增加了并发编程的支持,包括原子操作、互斥量、条件变量等,可以实现线程间的同步和通信。
9.异常处理:C++11引入了新的异常处理机制,包括了无异常声明的函数、异常类型的推导等,使得异常处理更加安全和高效。
10.容器和算法增强:C++11引入了新的容器和算法,如unordered_map、unordered_set、移动语义可用的容器和算法等,提高了效率和代码的可读性。
以上是C++11面试的一些核心知识点,面试时可以根据具体情况深入了解和准备。
auto_ptr到底能不能作为容器的元素?【摘要】对C++语言本身来说,它并不在乎用户把什么类型的对象作为STL容器的元素,因为模板类型参数在理论上可以为任何类型。
比如说STL容器仅支持“值”语义而不支持“引用(&)”语义,并非因为模板类型参数不能为引用,而是因为如果容器元素为引用类型,就会出现“引用的引用”、“引用的指针”等C++语言不支持的语法和语义。
智能指针是一种模拟原始指针行为的对象,因此理论上也可以作为容器的元素,就象原始指针可以作为容器元素一样。
但是智能指针毕竟是一种特殊的对象,它们在原始指针共享实值对象的基础能力上增加了自动销毁实值对象的能力,如果将它作为容器的元素,可能导致容器之间共享元素对象实值,这不仅不符合STL容器的概念和“值”语义,也会存在安全隐患,同时也会存在许多应用上的限制,特别是象STL中的auto_ptr这样的智能指针。
本文深入地阐述了auto_ptr这种较简单的智能指针“可以”或者“不可以”作为容器元素的根本原因,以及它作为容器元素会存在的限制和带来的问题,最后说明auto_ptr存在的真正意义、正确的使用方法以及它的替代品——带有引用计数能力的智能指针,当容器之间需要共享元素对象时,或者程序中存在大量的指针传递而担心资源泄漏时,这样的智能指针就特别有用。
【关键字】auto_ptr 容器智能指针一、引言Scott Meyers在《More Effective C++》[3]一书中对智能指针及其相关问题(构造、析构、复制、提领、测试以及类型转换等)作了深入的分析,其中也提到“STL的auto_ptr这种在复制时会把对实值对象的拥有权转交出去的智能指针不宜作为STL容器的元素”,而且在他的《Effective STL》[4]Item 8中明确指出了这一点。
Nicolai M.Josuttis的《The C++ Standard Library》[5]中有一节专门针对auto_ptr的阐述也指出“auto_ptr不满足STL标准容器对元素的最基本要求”。
STL教程:C++ STL快速入门(非常详细)
STL 是“Standard Template Library”的缩写,中文译为“标准模板库”。
STL 是C++ 标准库的一部分,不用单独安装。
C++ 对模板(Template)支持得很好,STL 就是借助模板把常用的数据结构及其算法都实现了一遍,并且做到了数据结构和算法的分离。
例如,vector 的底层为顺序表(数组),list 的底层为双向链表,deque 的底层为循环队列,set 的底层为红黑树,hash_set 的底层为哈希表。
更多关于STL 的介绍请猛击:STL是什么
这套C++ STL 入门教程非常详细,旨在让您快速学会标准模板库的使用。
读者需要具备C++基础,并了解C++模板的用法。
智能指针(shared_ptr,unique_ptr)作为函数参数或者返回值时的⼀些注意事项智能指针(shared_ptr,unique_ptr)作为函数参数或者返回值时的⼀些注意事项当智能指针作为函数的参数或者返回值时,⼀直在纠结到底是⽤智能指针对象本⾝还是⽤原始指针。
Herb Sutter⼤师的⽂章很好的解决了这个疑惑,参见⽹址:总结起来如下1、不要传递shared_ptr本⾝,⽽是⽤原始指针。
因为会有性能损失,原⼦操作的⾃增⾃减等。
使⽤f(widget *w)不使⽤f(shared_ptr< widget > w)函数的返回值也是同样的道理。
2当表⽰所有权的转移时,⽤unique_ptr作为函数参数。
Guideline: Don’t pass a smart pointer as a function parameter unless you want to use or manipulate the smart pointer itself, such as to share or transfer ownership.Guideline: Prefer passing objects by value, *, or &, not by smart pointer.Guideline: Express a “sink” function using a by-value unique_ptr parameter.Guideline: Use a non-const unique_ptr& parameter only to modify the unique_ptr.Guideline: Don’t use a const unique_ptr& as a parameter; use widget* instead.Guideline: Express that a function will store and share ownership of a heap object using a by-value shared_ptr parameter.Guideline: Use a non-const shared_ptr& parameter only to modify the shared_ptr. Use a const shared_ptr& as a parameter only if you’re not sure whether or not you’ll take a copy and share ownership; otherwise use widget* instead (or if not nullable, a widget&).。
C++智能指针⽤法详解⼀、简介由于 C++ 语⾔没有⾃动内存回收机制,程序员每次 new 出来的内存都要⼿动 delete。
程序员忘记 delete,流程太复杂,最终导致没有delete,异常导致程序过早退出,没有执⾏ delete 的情况并不罕见。
⽤智能指针便可以有效缓解这类问题,本⽂主要讲解常见的智能指针的⽤法。
包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost:: intrusive_ptr。
你可能会想,如此多的智能指针就为了解决new、delete匹配问题,真的有必要吗?看完这篇⽂章后,我想你⼼⾥⾃然会有答案。
下⾯就按照顺序讲解如上 7 种智能指针(smart_ptr)。
⼆、具体使⽤1、总括(1)对于编译器来说,智能指针实际上是⼀个栈对象,并⾮指针类型,在栈对象⽣命期即将结束时,智能指针通过析构函数释放由它管理的堆内存;(2)所有智能指针都重载了“operator->”操作符,直接返回对象的引⽤,⽤以操作对象(参见);(3)访问智能指针原来的⽅法则使⽤“.”操作符;(4)访问智能指针包含的裸指针则可以⽤ get() 函数;(5)由于智能指针是⼀个对象,所以if (my_smart_object)永远为真,要判断智能指针的裸指针是否为空,需要这样判断:if(my_smart_object.get())。
(6)智能指针包含了 reset() ⽅法,如果不传递参数(或者传递 NULL),则智能指针会释放当前管理的内存。
如果传递⼀个对象,则智能指针会释放当前对象,来管理新传⼊的对象。
⾸先,我们编写⼀个测试类来辅助分析:class Simple {public:Simple(int param = 0){number = param;std::cout << "Simple: " << number << std::endl;}~Simple(){std::cout << "~Simple: " << number << std::endl;}void PrintSomething(){std::cout << "PrintSomething: " << info_extend.c_str() << std::endl;}std::string info_extend;int number;};2、std::auto_ptr——独占(《C++ Primer Plus》(第六版)中还有提及std::unique_ptr)std::auto_ptr 属于 STL,当然在 namespace std 中,包含头⽂件 #include<memory>便可以使⽤。
84、智能指针的原理、常⽤的智能指针及实现原理智能指针是⼀个类,⽤来存储指向动态分配对象的指针,负责⾃动释放动态分配的对象,防⽌堆内存泄漏。
动态分配的资源,交给⼀个类对象去管理,当类对象声明周期结束时,⾃动调⽤析构函数释放资源常⽤的智能指针(1) shared_ptr实现原理:采⽤引⽤计数器的⽅法,允许多个智能指针指向同⼀个对象,每当多⼀个指针指向该对象时,指向该对象的所有智能指针内部的引⽤计数加1,每当减少⼀个智能指针指向对象时,引⽤计数会减1,当计数为0的时候会⾃动的释放动态分配的资源。
a.智能指针将⼀个计数器与类指向的对象相关联,引⽤计数器跟踪共有多少个类对象共享同⼀指针b.每次创建类的新对象时,初始化指针并将引⽤计数置为1c.当对象作为另⼀对象的副本⽽创建时,拷贝构造函数拷贝指针并增加与之相应的引⽤计数d.对⼀个对象进⾏赋值时,赋值操作符减少左操作数所指对象的引⽤计数(如果引⽤计数为减⾄0,则删除对象),并增加右操作数所指对象的引⽤计数e.调⽤析构函数时,构造函数减少引⽤计数(如果引⽤计数减⾄0,则删除基础对象)(2) unique_ptrunique_ptr采⽤的是独享所有权语义,⼀个⾮空的unique_ptr总是拥有它所指向的资源。
转移⼀个 unique_ptr将会把所有权全部从源指针转移给⽬标指针,源指针被置空;所以unique_ptr不⽀持普通的拷贝和赋值操作,不能⽤在STL标准容器中;局部变量的返回值除外(因为编译器知道要返回的对象将要被销毁);如果你拷贝⼀个unique_ptr,那么拷贝结束后,这两个unique_ptr都会指向相同的资源,造成在结束时对同⼀内存指针多次释放⽽导致程序崩溃。
(3) weak_ptrweak_ptr:弱引⽤。
引⽤计数有⼀个问题就是互相引⽤形成环(环形引⽤),这样两个指针指向的内存都⽆法释放。
需要使⽤weak_ptr打破环形引⽤。
weak_ptr是⼀个弱引⽤,它是为了配合shared_ptr ⽽引⼊的⼀种智能指针,它指向⼀个由shared_ptr管理的对象⽽不影响所指对象的⽣命周期,也就是说,它只引⽤,不计数。
一.基本概念先来看看栈。
栈,一般用于存放局部变量或对象,如我们在函数定义中用类似下面语句声明的对象:Type stack_object ;stack_object便是一个栈对象,它的生命期是从定义点开始,当所在函数返回时,生命结束。
另外,几乎所有的临时对象都是栈对象。
比如,下面的函数定义:Type fun(Type object) ;这个函数至少产生两个临时对象,首先,参数是按值传递的,所以会调用拷贝构造函数生成一个临时对象object_copy1 ,在函数内部使用的不是使用的不是object,而是object_copy1,自然,object_copy1是一个栈对象,它在函数返回时被释放;还有这个函数是值返回的,在函数返回时,如果我们不考虑返回值优化(NRV),那么也会产生一个临时对象object_copy2,这个临时对象会在函数返回后一段时间内被释放。
比如某个函数中有如下代码:Type tt ,result ; //生成两个栈对象tt = fun(tt) ; //函数返回时,生成的是一个临时对象object_copy2上面的第二个语句的执行情况是这样的,首先函数fun返回时生成一个临时对象object_copy2 ,然后再调用赋值运算符执行tt = object_copy2 ; //调用赋值运算符看到了吗?编译器在我们毫无知觉的情况下,为我们生成了这么多临时对象,而生成这些临时对象的时间和空间的开销可能是很大的,所以,你也许明白了,为什么对于“大”对象最好用const引用传递代替按值进行函数参数传递了。
接下来,看看堆。
堆,又叫自由存储区,它是在程序执行的过程中动态分配的,所以它最大的特性就是动态性。
在C++中,所有堆对象的创建和销毁都要由程序员负责,所以,如果处理不好,就会发生内存问题。
如果分配了堆对象,却忘记了释放,就会产生内存泄漏;而如果已释放了对象,却没有将相应的指针置为NULL,该指针就是所谓的“悬挂指针”,再度使用此指针时,就会出现非法访问,严重时就导致程序崩溃。
一.题型:问答五题,程序两题,选择10来题二.题目1.堆和栈的区别与联系(C/C++的内容,不是数据结构的内容)1、栈区(stack)由编译器自动分配释放,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈。
2、堆区(heap)一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事。
区别:1.管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生内存溢出。
2. 空间大小:堆内存几乎是没有什么限制。
栈一般都是有一定的空间大小。
3. 碎片问题:对于堆来讲,频繁的new/delete会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。
对于栈来讲,则不会存在这个问题。
4. 分配方式:堆都是动态分配的,没有静态分配的堆。
栈有2种分配方式:静态分配和动态分配。
5. 分配效率:栈的效率比较高。
堆的效率比栈要低得多。
见:3f重载和覆盖的区别与联系重载是指不同的函数使用相同的函数名,但函数的参数个数或类型不通。
调用的使用根据函数的参数来区别不同的函数。
覆盖是指派生类中重新对基类的虚函数重新实现。
即函数名和参数都一样,只是函数的实现体不一样。
3.什么是多重继承,好处及缺点多重继承指的是一个类别可以同时从多于一个父类继承行为与特征的功能。
优点:可以使用多重继承编写非常复杂、但很紧凑的代码,如C++ ATL库。
缺点:出现二义性、虚函数、访问权限等问题,容易产生混淆。
4.做过什么项目.遇到什么问题(不写似乎没事)自己想吧,根据自己情况写5.不用第三个变量交换两个int型的值(必须用C实现)int a = 2, b = 3;a=a+b;b=a-b;a=a-b;6.链表删除操作此处实现删除链表中的第二个元素。
int * p, * q ,* list ;写一个程序,堆可以访问,栈不可以访问。
写一个程序,栈可以访问,堆不可以访问。
C++智能指针(auto_ptr)详解
(2012-04-19 23:29:16)
转载▼
标签:
分类:软件程序
c
auto_ptr
智能指针
内存
it
智能指针(auto_ptr)这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限。
本文总结的8个问题足以涵盖auto_ptr的大部分内容。
1. auto_ptr是什么?
auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者。
当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放。
即使发生异常,通过异常的栈展开过程也能将动态内存释放。
auto_ptr不支持new 数组。
2. auto_ptr需要包含的头文件?
#include <memory>
3. 初始化auto_ptr对象的方法?
1) 构造函数
1] 将已存在的指向动态内存的普通指针作为参数来构造
int* p = new int(33);
auto_ptr<int> api(p);
2] 直接构造智能指针
auto_ptr< int > api( new int( 33 ) );
2) 拷贝构造
利用已经存在的智能指针来构造新的智能指针
auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) );
auto_ptr< string > pstr_auto2( pstr_auto ); //利用pstr_auto来构造pstr_auto2因为一块动态内存智能由一个智能指针独享,所以在拷贝构造或赋值时都会发生拥有权转移的过程。
在此拷贝构造过程中,pstr_auto将失去对字符串内存的所有权,而pstr_auto2将其获得。
对象销毁时,pstr_auto2负责内存的自动销毁。
3) 赋值
利用已经存在的智能指针来构造新的智能指针
auto_ptr< int > p1( new int( 1024 ) );
auto_ptr< int > p2( new int( 2048 ) );
p1 = p2;
在赋值之前,由p1 指向的对象被删除。
赋值之后,p1 拥有int 型对象的所有权。
该对象值为2048。
p2 不再被用来指向该对象。
4. 空的auto_ptr 需要初始化吗?
通常的指针在定义的时候若不指向任何对象,我们用Null给其赋值。
对于智能指针,因为构造函数有默认值0,我们可以直接定义空的auto_ptr如下:
auto_ptr< int > p_auto_int; //不指向任何对象
5. 防止两个auto_ptr对象拥有同一个对象(一块内存)
因为auto_ptr的所有权独有,所以下面的代码会造成混乱。
int* p = new int(0);
auto_ptr<int> ap1(p);
auto_ptr<int> ap2(p);
因为ap1与ap2都认为指针p是归它管的,在析构时都试图删除p, 两次删除同一个对象的行为在C++标准中是未定义的。
所以我们必须防止这样使用auto_ptr。
6. 警惕智能指针作为参数!
1) 按值传递时,函数调用过程中在函数的作用域中会产生一个局部对象来接收传入的auto_ptr(拷贝构造),这样,传入的实参auto_ptr就失去了其对原对象的所有权,而该对象会在函数退出时被局部auto_ptr删除。
如下例:
void f(auto_ptr<int> ap)
{cout<<*ap;}
auto_ptr<int> ap1(new int(0));
cout<<*ap1; //错误,经过f(ap1)函数调用,ap1已经不再拥有任何对象了。
2) 引用或指针时,不会存在上面的拷贝过程。
但我们并不知道在函数中对传入的auto_ptr 做了什么,如果当中某些操作使其失去了对对象的所有权,那么这还是可能会导致致命的执行期错误。
结论:const reference是智能指针作为参数传递的底线。
7. auto_ptr不能初始化为指向非动态内存
原因很简单,delete 表达式会被应用在不是动态分配的指针上这将导致未定义的程序行为。
8. auto_ptr常用的成员函数
1) get()
返回auto_ptr指向的那个对象的内存地址。
如下例:
int* p = new int(33);
cout << "the adress of p: "<< p << endl;
auto_ptr<int> ap1(p);
cout << "the adress of ap1: " << &ap1 << endl;
cout << "the adress of the object which ap1 point to: " << ap1.get() << endl;
输出如下:
the adress of p: 00481E00
the adress of ap1: 0012FF68
the adress of the object which ap1 point to: 00481E00
第一行与第三行相同,都是int所在的那块内存的地址。
第二行是ap1这个类对象本身所在内存的地址。
2) reset()
重新设置auto_ptr指向的对象。
类似于赋值操作,但赋值操作不允许将一个普通指针指直接赋给auto_ptr,而reset()允许。
如下例:
auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) );
pstr_auto.reset( new string( "Long -neck" ) );
在例子中,重置前pstr_auto拥有"Brontosaurus"字符内存的所有权,这块内存首先会被释放。
之后pstr_auto再拥有"Long -neck"字符内存的所有权。
注:reset(0)可以释放对象,销毁内存。
3) release()
返回auto_ptr指向的那个对象的内存地址,并释放对这个对象的所有权。
用此函数初始化auto_ptr时可以避免两个auto_ptr对象拥有同一个对象的情况(与get
函数相比)。
auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) );
auto_ptr< string > pstr_auto2( pstr_auto.get() ); //这是两个auto_ptr拥有同一个对象
auto_ptr< string > pstr_auto2( pstr_auto.release() ); //release可以首先释放所有权。