Skip to content

Commit 7502ce5

Browse files
committed
update
1 parent bdc521c commit 7502ce5

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed

content/posts/learncpp_1/index.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
title: "cpp学习笔记(1)"
3+
date: 2025-09-11T08:10:38+08:00
4+
draft: false
5+
lastmod: 2025-09-20T21:59:46+08:00
6+
---
7+
8+
## 前言
9+
10+
最近找到个个还不错的[网站](https://learncpp.com),适合我这种大白,遂开始学习,记录一些感受。
11+
12+
此系列可能没有很好的排版,因为是给自己看的。
13+
14+
不保证所有的内容一定正确,因为是学习过程中记录的,所以可能还会有完全不正确的理解。
15+
16+
## 澄清一个我混淆的概念
17+
18+
表达式:求值,调用函数,变量/常量和运算符相结合的东西
19+
20+
语句:有分号的东西,可以由多个表达式复合而成。
21+
22+
statement expression(原谅我不会翻译):只含一个表达式的语句。
23+
24+
标识符:用户自定义的名称,不以数字开头。
25+
26+
关键字:系统保留字,用于流程控制。
27+
28+
## cin/cout探秘
29+
30+
我一直好奇,`<<`是怎么实现的,还能同时接着,是怎么使用的。
31+
32+
事实上,这运用的是运算符重载,语义分析会处理左右两边的表达式,然后决定是否重载它。
33+
34+
`<<`是左结合的,所以优先处理左边的部分。`<<`一看到左边是一个`ostream`类型,右边是一个字符串,自动重载,通过运算返回一个`ostream`,接着再处理次级优先的,依次拼接一个完整的字符串流。
35+
36+
这里提到一个重要概念:副作用。
37+
38+
正常来说,一个函数应该要返回值。当我们只使用一个`<<`的时候,确实只用到了副作用,如果我们连在一起使用的时候,那么返回值就非常重要了。这是不是有点像fp,给定输入得到输出,接着成为另一个输入?
39+
40+
## 现代的初始化
41+
42+
现在c++推荐使用列表直接初始化,避免隐式类型转换。
43+
44+
如:`foo{}`
45+
46+
还有别的办法:
47+
48+
- 直接初始化:`foo(1)`
49+
- 间接列表初始化:`foo = {1}`
50+
51+
⚠️不推荐在同一行定义多个变量,因为会在git中导致diff不清晰。
52+
53+
## literal/variable
54+
55+
学过微机的人都知道,一个程序加载进内存,会分别放到代码段和数据段,接着获取到一些段(stack,pile)。
56+
57+
其中:
58+
59+
- 代码段是只读的,同时和堆栈段中间还相隔了一些部分,这是避免数据溢出破坏程序的运行。
60+
- 对于字面量来说,使用它,就直接到数据段里面取,没有分配给他额外的空间。
61+
- 而对于变量来说,使用它,先得从数据段中拷贝一份到栈/堆(假设初始化的话),接着读取这个地址指向的内容,才能进行访问。
62+
63+
---
64+
65+
## compile-time / runtime
66+
67+
> 什么是编译时和运行时的概念?
68+
69+
编译时:编译器在进行语法检查的时候。
70+
71+
运行时:程序真正运行的时候。
72+
73+
所以说,我们有下面的内容:
74+
75+
1. 标识符和编译时相对应,对象和运行时相对应。
76+
77+
2. 作用域(scope)和编译时对应,生命周期(lifetime)和运行时相对应。
78+
79+
3. 同时还有一个大杀器:`constexpr`
80+
81+
这个关键字的意思,指的是能够在编译时就确定常量(甚至函数),而不是运行时,从而把运行时开销转换成编译时间,这是不是算是性能优化呢?
82+
83+
需要注意的是,在C++11~20的不同版本中,支持的类型略有差异,比如后期才支持流程控制的for/while/if。
84+
85+
感觉gemini这么说不错:
86+
87+
> 标识符是编译时的抽象,是对象在代码中的名字和类型。
88+
> 对象是运行时的实体,是标识符所代表的内存和数据。
89+
90+
91+
## cmake的一些使用方法(对于多文件/引入libs)
92+
93+
94+
1. 加入这一行把需要的头包含进来,就可以直接在#include里面写`.h`的文件了,无须写相对路径。
95+
96+
```cmake
97+
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/)
98+
```
99+
100+
2. 在cmake 3.30之后,引入Boost直接用`find_package(Boost)`就好。
101+
102+
## Best Practise
103+
104+
1. 尽量在使用一个变量的正前面初始化。
105+
106+
2. 尽量不要使用无符号整形,因为其具有的环绕特性会在一些行为(比如与有符号整数比较)上面让人难以调试。

content/posts/learncpp_2/index.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
+++
2+
date = '2025-09-19T19:13:57+08:00'
3+
draft = true
4+
title = 'cpp学习笔记(2)'
5+
+++
6+
## 符号变量
7+
8+
magic number这个词,我一直认为是大家约定好了的一组数,但是这里是不同的含义。
9+
10+
它指的是直接放在函数里面,没有任何交代的数据,使得程序更加难读。
11+
12+
所以做法一般是推荐用`const`修饰,如果标准高的话,`constexpr`,请。
13+
14+
## 字符串
15+
16+
从c开始那么久,都一直没认真了解过字符串,这会终于明白了`std::string`的一些基本操作。
17+
18+
众所周知,字符串里面不可避免包含空白字符,那么办法就是通过`std::getline()`,但是如果在`std::cin`之后使用,大概率这么传入`(std::cin, target)`是无效的,因为`cin`在读到空白字符之后会停止,并且把空白字符留在缓冲区,那么下一次读取的时候,直接就把一个`\n`传入了,所以你的字符串啥都没有。
19+
20+
问题解决是通过流操纵符`std::ws`(这个需要每次cin的时候都提供),控制如果一开始就读取到空白字符,那么就忽略掉这个字符继续读取后面的东西。
21+
22+
这时就很好的解决了读取到`\n`的问题,除非读取到下一个`\n`,那么`getline`才停止读取,此时字符串也成功存入了这一行。
23+
24+
怎么说呢,感觉比c先进一点点(?
25+
26+
## string_view
27+
28+
```cpp
29+
// 用string_view指向string的话,不产生多余的拷贝,只是在初始化的时候拷贝进入string
30+
std::string name {"John"}; //此处产生拷贝
31+
std::string_view name_v {name}; // 不拷贝
32+
33+
// 实际上,是让string_view指向一个c风格的字符串,这个过程没有拷贝。
34+
std::string_view name {"John"};
35+
```
36+
如果常量能够在编译时确定,那么就可以应用`constexpr`。很显然,前者是不可行的,后者可以。
37+
38+
---
39+
40+
> ⚠️ string_view的行为与普通的引用和指针不一致。
41+
42+
43+
当用`string`来初始化`string_view`,然后`string`被修改之后,`string_view`并不会更新`string`的新长度。
44+
45+
如果要避免,得更新视图。(不知道智能指针是否有帮助?)
46+
47+
---
48+
49+
不建议用`string_view`来返回,除非它是用C式的字符串初始化的。

date --iso9001=seconds

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
date:

0 commit comments

Comments
 (0)