五、C++11
(1)请问C++11有哪些新特性?
1. auto关键字:编译器可以根据初始值自动推导出类型。//但是不能用于函数传参以及数组类型的推导 2. nullptr关键字:nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型。而NULL一般被宏定义为0,在遇到重载时可能会出现二义性问题。 3. 智能指针:C++11新增了shared_ptr,weak_ptr,unique_ptr,auto_ptr用来管理内存 4. 初始化列表:使用初始化列表来对类进行初始化 5. 右值引用:基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
参考回答2: 1. 关键字及新语法 auto关键字 nullptr关键字 for循环 2. STL容器 std::array std::forward_list std::unordered_set std::unordered_map 3. 多线程 std::thread std::atomic std::condition_variable 4. 智能指针内存管理 5. 其他 std::function、std::bind封装可执行对象 lambda表达式 右值引用 可变参数模板
(2)NULL和nullptr的区别?
https://blog.csdn.net/qq_18108083/article/details/84346655
nullptr的出现时为了解决NULL表示空指针在C++中具有二义性的问题
#include <iostream> using namespace std; void func(void* i) { cout << "func1" << endl; } void func(int i) { cout << "func2" << endl; } void main(int argc,char* argv[]) { func(NULL); func(nullptr); getchar(); }
在这段代码中,我们对函数func进行可重载,参数分别是void*类型和int类型,但是运行结果却与我们使用NULL的初衷是相违背的,因为我们本来是想用NULL来代替空指针,但是在将NULL输入到函数中时,它却选择了int形参这个函数版本,所以是有问题的,这就是用NULL代替空指针在C++程序中的二义性。
(3)可变参数模板
C++11 的可变参数模板,对参数进行了高度泛化,可以表示任意数目、任意类型的参数,其 语法为:在 class 或 typename
template<class ... T> void func(T ... args) { cout << "num is " << sizeof ...(args) << endl; } int main() { func(); func(1); func(1, 2.0); system("pause"); return 0; }
(4)左值引用、右值引用?
C++ Primer中P471页
C++中定义了引用类型,存在左值引用。在C++11中新增了右值引用。
https://blog.csdn.net/qq_21989927/article/details/108525880
左值:非临时性对象的表达式,有名字,可以取地址。 右值:临时性对象的表达式,没有名字,临时生成的,不可以取地址。如:立即数、函数的返回值。
右值引用只能绑定一个将要销毁的对象,我们可以自由地将一个右值引用的资源“移动”到另一个对象。通过&&来获得右值引用。 //右值引用的主要目的是为了实现转移语义和完美转发,消除两个对象交互时不必要的对象拷贝,也能够更加简洁明确地定义泛型函数。 避免拷贝,提高性能,实现move()
int &&r = 42; //正确,字面常量是右值 int &&r2 = r; //错误,r1是左值 //虽然不能将一个右值引用直接绑定到一个左值上,但我们可以显式地将一个左值转换为对应的右值引用类型 int &&r3 = std::move(r); //OK
(5)lambda表达式
(6)智能指针
为什么要使用智能指针? 智能指针的作用是管理一个指针。new申请的空间在函数结束时忘记释放,会造成内存泄漏。使用智能指针可以避免这个问题,因为智能指针是一个类,当超出了类的作用域时,类会自动调用析构函数释放内存,不需要手动释放内存空间。
四种智能指针:auto_ptr、unique_ptr、shared_ptr、weak_ptr 1. auto_ptr 实现独占式拥有的概念,同一时间只能有一个智能指针可以指向该对象,但auto_ptr在C++11中被摒弃,其问题在于: * 对象所有权的转移。比如在函数传参过程中,对象所有权不会返还,从而存在潜在的内存奔溃问题。 * 不能指向数组,也不能作为STL容器的成员。 auto_ptr<string> p1 (new string ("aaaaaa")); auto_ptr<string> p2; p2 = p1; //auto_ptr不会报错 此时不会报错,p2剥夺了p1的所有权,但是当程序运行时访问p1将会报错。所以auto_ptr存在潜在的内存奔溃问题。 2. unique_ptr(替代auto_ptr) 实现独占式拥有的概念,同一时间只能有一个智能指针可以指向该对象,因为无法进行拷贝构造和拷贝赋值,但是可以进行移动构造和移动赋值。 unique_ptr<string> p1 (new string ("aaa")); unique_ptr<string> p2; p2 = p1; //报错 另外unique_ptr还有更聪明的地方,当程序试图将一个unique_ptr赋值给另一个时,如果源unique_ptr是个临时右值,编译器允许这么做;如果源unique_ptr将存在一段时间,编译器将禁止这么做。 unique_ptr<string> pu1(new string("hello world")); unique_ptr<string> pu2; pu2 = pu1; //#1 not allowed unique_ptr<string> pu3; pu3 = unique<string>(new string("You")); //#2 allowed 3. shared_ptr 实现共享式拥有的概念,即多个智能指针可以在指向相同的对象,该对象及相关资源会在其所指对象不再使用之后,自动释放与对象相关的资源。 4.weak_ptr weak_ptr是一种不控制对象生命周期的智能指针,它指向一个shared_ptr管理的对象。weak_ptr只是提供了对管理对象的一个访问手段,weak_ptr设计的目的是为了配合shared_ptr而引入的一种智能指针来协助shared_ptr工作。 解决shared_ptr相互引用时,两个指针的引用计数永远不会下降为0,从而导致死锁的问题。 weak_ptr是对对象的一种弱引用,可以绑定到shared_ptr,但不会增加对象的引用计数。
问:shared_ptr是如何实现的? 1. 构造函数中计数初始化为1 2. 拷贝构造函数中计数值加1 3. 赋值运算符中,左边的对象引用计数减1,右边的对象引用计数加1 4. 析构函数中引用计数减1 5. 在赋值运算符和析构函数中,如果减1后为0,则调用delete释放对象。
智能指针有没有内存泄漏的情况?
当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
class Parent; class Child; class Parent { private: shared_ptr<Child> ChildPtr; public: void setChild(shared_ptr<Child> child) { this->ChildPtr = child; } void doSomething() { if (this->ChildPtr.use_count()) { } } ~Parent() {} }; class Child { private: shared_ptr<Parent> ParentPtr; public: void setParent(shared_ptr<Parent> parent) { this->ParentPtr = parent; } void doSomething() { if (this->ParentPtr.use_count()) { } } ~Child() {} }; int main() { weak_ptr<Parent> wpp; weak_ptr<Child> wpc; { shared_ptr<Parent> p(new Parent); shared_ptr<Child> c(new Child); p->setChild(c); c->setParent(p); wpp = p; wpc = c; cout << p.use_count() << endl; //2 cout << c.use_count() << endl; //2 } cout << wpp.use_count() << endl; //1 cout << wpc.use_count() << endl; //1 }
智能指针的内存泄漏如何解决?
为了解决循环引用导致的内存泄漏,引用了weak_ptr弱指针,weak_ptr的构造函数不会修改引用计数的值,从而不会对对象的内存进行管理,其类似一个普通指针,但不指向引用计数的共享内存,但是其可以检测到所管理的对象是否已经被释放,从而避免非法访问。