Interview_C++_day14
i++ 和 ++i 的区别
++i 返回对象的引用,i++ 必须产生一个临时对象保存更改前对象的值并返回,所以导致在大对象的时候产生的比较大的复制开销,效率较低。
// ++i
int& int::operator++() {
*this += 1;
return *this;
}
// i++
const int int::operator++(int) {
int old_value = *this;
++(*this);
return old_value;
}
拷贝构造函数
Node a;
Node b(a);
Node c = a;
这里的 b 和 c 都是一开始是不存在的,是通过 a 对象来构造和初始化的。
拷贝构造函数重载形式:
Node (const Node &other) {
}
如果用户没有自定义拷贝构造函数并且用到了拷贝构造函数,则编译器会生成默认的拷贝构造函数。
在 C++ 中,这三种情况下拷贝构造函数会被使用:
- 一个对象以值传递的形式传入函数内。
- 一个对象以值传递的形式从函数返回。
- 一个对象通过另一个对象初始化。
优点:可以很容易的复制对象。
缺点:对象的隐式拷贝是 C++ 中是错误和性能问题的来源之一。它也降低了代码的可读性,并使得对象子程序中的传递和改变变得难以跟踪。
赋值函数
Node a;
Node b;
b = a;
这里的 b 已经存在的,在通过 a 赋值给 b。
赋值函数重载形式:
Node& operator=(const Node &other) {
}
拷贝构造函数和赋值函数区别
- 拷贝构造函数是在对象初始化时,分配一块空间并初始化,而赋值函数是对已经分配空间的对象进行赋值操作。
- 实现上,拷贝构造函数是构造函数,通过参数的对象初始化产生一个对象。赋值函数则是把一个对象赋值给另一个对象,需要先判断两个对象是否是同一个对象,若是则什么都不做,直接返回,若不是则需要先释放原对象内存,在赋值。(可以参考 shared_ptr实现)
总结:
- 对象不存在,没有通过别的对象来初始化,就是构造函数。
- 对象不存在,通过别的对象来初始化,就是拷贝构造函数。
- 对象存在,通过别的对象来初始化,就是赋值函数。
虚函数和内联函数
内联函数通常就是将它在调用处 "内敛的" 展开,消除反复调用的额外开销,但是如果函数太长,会使代码臃肿,反而降低效率。
虚函数可以是内联函数,无论是显式还是隐式,inline 都只是一个申请,最终由编译器决定是否内联。所以可以用 inline 修饰虚函数,但虚函数表现多态性时,不可以内联,只有当知道调用哪个类的函数时,才可以是内联。
空类的大小
在 C++ 中规定类的大小不为 0,空类大小为 1,当类不包含虚函数和非静态成员时,其对象大小也为 1。若存在虚函数,则需要存储一个虚函数指针大小,在 32 位上为 4 字节。
结构体字节对齐
class A {
};
class B{
public:
A x;
};
sizeof(B) = 1
class B{
public:
inline virtual fun() {
}
};
sizeof(B) = 4
class B{
public:
A x;
inline virtual fun() {
}
};
sizeof(B) = 8
可以发现最后一个的 sizeof 并不是单纯的 1+4=5,而直接变成了 8,因为存在结构体的字节对齐规则。
结构体字节对齐的根本原因: 1) 移植性更好,某些平台只能在特定的地址访问特定的数据。2) 提高存取数据的速度,CPU 通常按块读取数据会更加快速。
结构体字节对齐原则:
- 无 #pragma pack
- 结构内部各成员首地址必然是 自身大小 的整数倍。
- sizeof 最终结果必然是 结构内部最大成员 的整数倍,不够补齐
- 有 #pragma pack(n)
- 结构内部各成员首地址必然是 min(n,自身大小) 的整数倍。
- sizeof 最终结果必然是 min(n,结构内部最大成员) 的整数倍,不够补齐。
#include<bits/stdc++.h>
using namespace std;
class A {
char a;
int b;
short c;
};
class B {
int a;
char b;
short c;
};
int main() {
cout << sizeof(A) << endl; // 12
cout << sizeof(B) << endl; // 8
return 0;
}
造成不同结果的原理在于:
- 对于 classA 来说,内部字节为
a | b | c |
---|---|---|
1*** | 1111 | 11** |
- 对于 classB 来说,内部字节为
a | b | c |
---|---|---|
1111 | 1* | 11 |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· 一个适用于 .NET 的开源整洁架构项目模板
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手
· .NET 9.0 使用 Vulkan API 编写跨平台图形应用
· MyBatis中的 10 个宝藏技巧!