结构体定义
C:
typedef struct Vertex {
int x, y, z;
} Vertex;
Vertex v1 = { 0 };
// or
struct Vertex {
int x, y, z;
};
struct Vertex v1 = { 0 };
C++:
struct Vertex {
int x, y, z;
};
Vertex v1 = {};
如果你一开始学的C++,再去写C的时候,你就会一脸懵逼怎么我的结构体编译不了。。。
为特定类型分配堆内存
C:
Vertex* ptr = malloc(sizeof(Vertex) * 10);
free(ptr);
C++:
Vertex* ptr = new Vertex[10];
delete[] ptr;
malloc 的参数是字节,所以得配合 sizeof 用。C++ 的 new 参数是个数,自动根据类型分配对应字节,看起来可读性更强。malloc始终返回的是 void*
, C 里面 void*
可以任意转换到其他类型的指针。C++ 的 new 返回的是指定类型的指针,类型系统进更加严格。
计算固定大小数组的元素个数
C:
Vertex arr[1024];
int arrSize = sizeof(arr) / sizeof(Vertex);
C++:
Vertex arr[1024];
int arrSize = std::size(arr);
你当然可以写死 int arrSize = 1024; 但这样就不优雅了,不爽了。
RAII
C 语言经常出现 alloc、free 这样用来创建销毁资源的成对函数,新手很容易忘记调用 free 导致内存泄漏:
Ball* ball = ball_alloc();
// ...
while (ball->isLive) {
// ...
if (ball->size > 5) {
return; // 哦豁,完蛋
}
}
ball_free(ball);
return;
特别是各种条件判断里面带 return 的,可能有人觉得在条件里面写 return 那是你代码风格有问题,这个就见仁见智了。
C++ 只要你写好析构函数,那以上问题你就不需要操心:
class Ball {
public:
Ball ();
~Ball ();
}
void foo () {
Ball ball();
// ...
while (ball.isLive) {
// ...
if (ball.size > 5) {
return;
}
}
return;
} // 退出 foo 函数之前必定会执行 ~Ball
准确来说,C++ 变量结束生命周期的时候,就会执行它对应的析构函数,再具体一点,就是当你离开一个大括号的范围时,在这个大括号里面创建的变量,都会析构,比如 for while 循环里面创建的变量,或者是 if 语句块里面创建的变量都是这样的,或者干脆你自己在中间写一个大括号:
int main () {
{
Ball ball;
printf("");
} // 这里 ball 会析构
return 0;
}
可惜 C++ 不能从语句块返回一个值,rust 就有这个不错的特性。
引用
引用用的好,指针不需要,当你用引用可以解决问题的时候,就别用指针。引用不存在野指针这类情况,他的作用范围更加严格。对引用操作,就是对本体操作,也不需要和指针一样用 ->
,直接 .
就好。指针类型的变量需要内存空间来存储一个内存地址,而引用只是一个别名,不需要空间存储内存地址。对于 a.b.c.d
这样一长串的表达式,用引用会更舒服(auto& d = a.b.c.d
)。
rust语言里面变量所有权概念,就是对C++引用拓展而已。
动态数组 vector
前面说了 C++ 的 new 是个好东西,但是 vector 更好。vector 本身有析构函数,生命周期结束自动调用里面每一个对象的析构函数,所以不用像 new 一样需要 delete。通常 C语言函数 传入一个数组,一般需要同时传入数组指针和数组大小,但是 C++ 你可以直接把 vector 当参数传入,本身就可以调用 size() 获取大小。
C:
void foo (Vertex* arr, int size) {
// ...
}
C++:
void foo (vector<Vertex>& arr) {
// ...
}
C++ 可以*选择传引用还是传值,C语言只能传指针。即便你在参数写上 Vertex arr[10],你以为他就能传值了?错了,当你想用 sizeof (arr) 得到数组大小时,它返回的是指针的大小,所以这就说明传进来的还是指针。
同样的道理,当你想返回数组,在函数返回类型写上 Vertex[10] 的时候,也是不行的,没有这样的写法,即便是固定大小的数组都不行。所以很多 C API 需要返回数组的时候怎么办?答案就是,你先自己分配好内存,再把指针传进去,他写入内容。那如果你也不知道数组长度多少怎么办,那一般会有一个API负责可以返回大小。
C++ 就爽快多了,你直接返回你在函数里面创建的 vector 就行,编译器会很贴心把这个变量的生命周期转移给调用者,不会发生任何额外复制。
C:
{
int size = GetSize();
Ball* balls = malloc(sizeof(Ball) * size);
GetBalls(balls, size);
free(balls);
}
C++:
{
vector<Ball> balls = GetBalls();
// 爽爽爽
}
对了,vector<bool>
请谨慎使用