五、C++11常见面试题

简介: 五、C++11常见面试题

五、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的构造函数不会修改引用计数的值,从而不会对对象的内存进行管理,其类似一个普通指针,但不指向引用计数的共享内存,但是其可以检测到所管理的对象是否已经被释放,从而避免非法访问。
目录
相关文章
|
6月前
|
存储 算法 编译器
C++面试题其一
C++文件编译与执行的四个阶段 预处理:处理#include、#define等预处理指令。 编译:将源码翻译为目标代码。 汇编:将目标代码转换为机器指令。 链接:将目标文件和库文件合并生成可执行文件。 STL中的vector的实现,是怎么扩容的? vector通过动态数组实现,当容量不足时,分配更大的内存(通常是原来的两倍),复制旧数据到新内存,并释放旧内存。
86 2
|
6月前
|
存储 程序员 编译器
C++面试题其二
extern "C" 用于告诉编译器按照C语言的链接方式处理代码,通常用于C++代码与C代码混合编程,以防止因名字修饰(name mangling)引起的链接错误。例如: extern "C" { void c_function(); } 通过这些问题的深入理解和解答,能够更好地掌握C++编程的核心概念和实际应用,为面试做好充分的准备。
81 1
|
6月前
|
存储 网络协议 编译器
【干货总结】Linux C/C++面试知识点
Linux C/C++基础与进阶知识点,不仅用于面试,平时开发也用得上!
624 17
|
7月前
|
存储 算法 C语言
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
69 5
|
7月前
|
存储 编译器 C语言
从C语言到C++_23(多态)抽象类+虚函数表VTBL+多态的面试题(下)
从C语言到C++_23(多态)抽象类+虚函数表VTBL+多态的面试题
68 1
|
7月前
|
存储 编译器 Linux
从C语言到C++_23(多态)抽象类+虚函数表VTBL+多态的面试题(中)
从C语言到C++_23(多态)抽象类+虚函数表VTBL+多态的面试题
70 1
|
6月前
|
安全 算法 C++
C++面试题其三
继续上篇博客的解答,我们将进一步探讨C++中的一些关键概念和常见面试问题。
59 0
|
7月前
|
编译器 C语言 C++
从C语言到C++_23(多态)抽象类+虚函数表VTBL+多态的面试题(上)
从C语言到C++_23(多态)抽象类+虚函数表VTBL+多态的面试题
51 0
|
7月前
|
编译器 程序员 C语言
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(下)
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题
50 0
|
7月前
|
编译器 C语言 C++
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(中)
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题
56 0