STL相关:interview/STL at master · huihut/interview · GitHub
1.static关键字
- 隐藏: static的全局变量和函数会对其它源文件隐藏
- 生命周期延长:被修饰的变量位于静态存储区, 对于静态局部变量,生命周期为整个程序而并非函数作用域
- 修饰类成员(静态成员变量和静态成员函数),静态成员变量和静态成员函数不属于任何对象,所有类实例所共有
- 默认初始化为0,并且只会第一次调用初始化
2.sizeof和strlen区别
- sizeof是运算符,在编译时计算; strlen是库函数,运行中调用
- sizeof参数可以是任何数据类型或数据; strlen参数只能是字符指针且结尾是'\0'的字符串
- sizeof值是在编译时确定,所以不能用来计算动态分配存储空间的大小
char *p = "abcdef";//字符串
char arr1[] = "abcdef";//字符串
char arr2[] = {'a','b','c','d','e','f'};//6个字符。没有\0
sizeof(p) = 8 ; // 指针大小为8字节(64位系统)
sizeof(arr1) = 7; //arr1为数组名,计算数组大小 + 末尾'\0'
sizeof(arr2) = 6; //和arr1区分,该情况末尾没有'\0'
strlen(p) = 6;
strlen(arr1) = 6;
strlen(arr2) = 不确定; //没有'\0',无法确定结束
char *p = "abcdef0\0a";//字符串
char arr1[] = "abcdef0\0a";//字符串
char arr2[] = {'a','b','c','d','e','f','0','\0','a'};
sizeof(p) = 8; //指针大小为8字节(64位系统)
sizeof(arr1) = 10; //'\0'算一个字符,加上末尾'\0'10个字符
sizeof(arr2) = 9; //没有结尾'\0'
strlen(p) = 7; //strlen均计算到'\0'之前
strlen(arr1) = 7;
strlen(arr2) = 7;
3.struct和class的区别
- 结构体的默认限定符是public;类是private。
4.malloc和new的区别
- malloc和free是标准库函数;new和delete是运算符,并且支持重载。
- malloc返回void*指针, new返回对象类型指针
- new/delete调用构造/析构函数,malloc/free不调用
- 分配内存大小: malloc必须显式指定字节数, new由编译器根据类型计算得出
- 分配失败返回值: new默认抛出异常, malloc返回NULL
- 处理数组:malloc计算数组大小后进行分配, new使用new[]处理 (注:delete[]会调用数组中每个元素的析构函数;delete和delete[]的区别:当delete常用类型数组(int char之类)时,delete和delete[]功能一样,但对于复杂类型,比如一个结构体数组(A k[] = new A[10]),delete k只会释放首元素,delete[]就会释放每个元素)
5.指针和引用的区别
- 指针保存的是所指对象的地址,引用是所指对象的别名,指针需要通过解引用间接访问,而引用是直接访问;
- 指针是具体变量,需要占用存储空间; 引用只是别名, 不占用具体存储空间;
- 指针可以改变地址,从而改变所指的对象,而引用必须从一而终;
- 引用在定义的时候必须初始化,而指针则不需要;
- 指针更灵活,用的好威力无比,用的不好处处是坑,而引用用起来则安全多了,但是比较死板。
左值和右值:
有地址的变量就是左值,没有地址的字面值、临时值就是右值。
左值引用和右值引用:
左值引用大家都很熟悉,能指向左值,不能指向右值的就是左值引用:
引用是变量的别名,由于右值没有地址,没法被修改,所以左值引用无法指向右值。
再看下右值引用,右值引用的标志是&&,顾名思义,右值引用专门为右值而生,可以指向右值,不能指向左值:
被声明出来的左、右值引用都是左值。
右值引用的目的:
-
移动语义:右值引用可以用于实现移动语义,这样可以避免重复构造对象,减少内存分配和复制的时间。因此,右值引用常用于函数返回值。
-
容器操作:右值引用可以被用于 STL 容器,如 vector、list 等,以实现快速插入和删除元素的操作。
-
临时对象的存储:右值引用可以用于存储临时对象,避免进行复制操作,从而提高程序效率。
-
返回大对象:右值引用可以用于返回大对象,避免复制和构造的操作,从而减少内存消耗。
引入右值引用,主要就是为了移动语义,C++11 std::move。移动语义就是为了减少拷贝。std::move就是将左值转为右值引用。这样就可以重载到移动构造函数了,移动构造函数将指针赋值一下就好了,不用深拷贝了,提高性能;
class Array {
public:
......
// 优雅
Array(Array&& temp_array) {
data_ = temp_array.data_;
size_ = temp_array.size_;
// 为防止temp_array析构时delete data,提前置空其data_
temp_array.data_ = nullptr;
}
public:
int *data_;
int size_;
};
int main(){
Array a;
// 做一些操作
.....
// 左值a,用std::move转化为右值
Array b(std::move(a));
}
int main() {
std::string str1 = "aacasxs";
std::vector<std::string> vec;
vec.push_back(str1); // 传统方法,copy
vec.push_back(std::move(str1)); // 调用移动语义的push_back方法,避免拷贝,str1会失去原有值,变成空字符串
vec.emplace_back(std::move(str1)); // emplace_back效果相同,str1会失去原有值
vec.emplace_back("axcsddcas"); // 当然可以直接接右值
}
// std::vector方法定义
void push_back (const value_type& val);
void push_back (value_type&& val);
void emplace_back (Args&&... args);
6.extern关键字
- extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义; 这是声明不是定义;
7.(1)define和typedef区别
- define用于定义常量及书写复杂的内容; typedef主要用于定义类型别名
- define作用于预处理阶段,属于文本替换; typedef是编译的一部分
- define不检查类型; typedef检查数据类型
- define不是语句,末尾不加分号; typedef是语句,要加分号标识结束
特别注意typedef和define在处理指针的时候的问题,如:
typedef int* pInt1;
#define pInt2 int*;
pInt1 a,b; //等价于 int *a; int *b; 定义了两个整型指针变量
pInt2 a,b; //等价于 int *a, b; 定义了整型指针a和整型变量b
(2)define和内联函数(inline)区别
inline关键字的作用:<

本文详细总结了C++面试中的重点知识,涵盖STL、static关键字、sizeof与strlen的区别、struct与class、malloc与new的对比、指针与引用、右值引用的用途、extern关键字、宏定义与typedef、内联函数与define、条件编译、常引用、指针常量与常量指针、指针类型解析、数组名与指针的区别、内存管理、虚函数与纯虚函数、重载、覆盖与隐藏、构造与析构函数调用顺序、深拷贝与浅拷贝、内存对齐、编译过程、智能指针、RAII机制、C++新特性、map与unordered_map的差异、类型转换、成员函数存储、单例模式实现等方面,是C++程序员秋招必备的知识梳理。
最低0.47元/天 解锁文章
16





