C++语言标准面试题精选
代码不标准,找bug两行泪。要想代码写得好,就要精通C++(和C++标准)。下面精选了一些无理取闹深入标准的造火箭面试题,供自己参考。
空结构体
- 在C语言中,空结构体的大小是0字节,因为什么都没有。
- 在C++中,每个对象都要有唯一的内存地址,空结构体的大小是1字节。
额外考点:STL模板库+内存填充
struct dummy {};
std::pair<int, dummy> p;
std::tuple<int, dummy> t;
pair
在实现中往往是一个sturct
,由此其内存大小为8(4+1+3)。tuple
在实例化模板时空结构体被编译器优化了,其内存大小为4。
参考资料:http://aequa.me/index.php/2019/08/01/why-stdpair-and-stdtuple-differ-in-size/
Lambda表达式
Lambda表达式在实现上实现了一个闭包类型,可以看作是一个重载了函数调用运算符operator()
的结构体。
- 按复制捕获的对象会在闭包中变为匿名非静态成员,按照对象大小分配内存单元;
- 按引用捕获的对象行为未定义,clang的实现大概是在闭包中放了个指针。
额外考点:隐式类型转换+内存填充
char a, b;
int c;
auto f1 = [=]() { a + b + c; };
auto f2 = [&]() { a + b + c; };
auto f3 = [=]() {};
void *(f4)() = [=]() {};
f1
是一个Lambda表达式,通过复制捕获了三个对象,其大小为8(内存填充)。f2
是一个Lambda表达式,通过引用捕获了三个对象,在64位机clang编译下其大小为24。f3
是一个Lambda表达式,没有捕获对象,其大小为1(空)。f4
是一个隐式转换得到的函数指针,64位机下其大小为8。
静态变量
以如下代码为例:
void foo() {
static i = 0;
cout << ++i << endl;
}
i
是函数的静态变量,会在编译时被初始化并存储在.bss
区,全局只有这一份数据。
额外考点:模板实例化
#include <iostream>
template <class T>
void foo(T) {
static i;
std::cout << ++i << std::endl;
}
int main() {
int a;
double b;
const int c;
foo(a), foo(b), foo(c);
}
const int
类型推导为int
。- 总共实例化了两个模板,输出为1、1、2。
重载决议
通过名称查找函数找到多个实例/模板时,需要进行重载决议。重载决议的细节很多,最重要的第一条比较规则就是隐式转换排行。
隐式转换共有三种级别,取最低等级:
- 准确匹配:不要求转换、左值到右值转换、限定性转换、函数指针转换、类类型到相同类的用户定义转换;
- 提升:整型提升、浮点提升;
- 转换:整型转换、浮点转换、浮点整型转换、指针转换、成员指针转换、布尔转换、派生类到其基类的用户定义转换。
类型提升(窄到宽)能够保留原有数据,是第二等级;而类型缩窄(宽到窄)属于整型/浮点转换,会丢失部分数据,属于最差的第三等级。
限定性转换也是有排行的,如果S1转换结果可以通过限定性转换转换为S2的结果,则S1更优。派生类到基类转换也是有排行的,如果如果S1转换结果可以通过上行/下行(同方向)转换为S2的结果,则S1更优。(简单的说就是转换越少越优)。
#include <iostream>
void foo(const int*, short) {
std::cout << "const int*, short" << std::endl;
};
void foo(int*, int) {
std::cout << "int*, int" << std::endl;
};
int main() {
int i = 0;
short s = 0;
foo(&i, s);
}
以上程序编译运行的结果是?
答案:按C++标准,以上程序无法编译。
原因:int* -> const int*
的隐式转换比不转换差,short -> int
的转换比不转换差,从可行重载函数集合中无法得到最优者。
参考资料:https://zh.cppreference.com/w/cpp/language/overload_resolution
好了,以上都学会(面向C++标准编程),你造的火箭就能送用这些题考核别人的人上天啦。
<EOF>
Loading Comments By Disqus