0
点赞
收藏
分享

微信扫一扫

五、C++11常见面试题

互联网码农 2022-05-06 阅读 18

五、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的构造函数不会修改引用计数的值,从而不会对对象的内存进行管理,其类似一个普通指针,但不指向引用计数的共享内存,但是其可以检测到所管理的对象是否已经被释放,从而避免非法访问。
举报

相关推荐

0 条评论