贡献者: addis
Matlab 和 Python 等动态语言虽然用起来方便,但缺点是运行较慢,对于一些计算量大的项目不适合。目前在高性能计算中广泛使用的只有两种语言即 C++ 和 Fortran。虽然 Fortran 普遍被认为是一个过时的语言,但在计算物理中,许多人仍然在使用,一是因为以前遗留下的 Fortran 代码比较多,二是一些年纪较大的学者只会 Fortran。
一本在数值算法中很有名的书是 Numerical Recipes,这本书第三版以前都使用 Fortran 或 C,而第三版却只有 C++,这也是本部分选择介绍 C++ 而不是 Fortran 的原因之一。本部分将从 Numerical Recipes 中借鉴许多代码上的风格和算法。
C++ 的特征实在多不胜数,事实上无论是什么语言,做计算物理的研究者大多会倾向于只选择一些最基础的语法来使用。我们在这里列出本部分使用的 C++ 特性。
在学习基本 C++ 语法时,强烈建议在 Jupyter Notebook 中使用 cling 解释器。这将节约大量的编译时间。
bool
, char
, int
, long
, long
long
, float
, double
,long double
)char, short, int
几乎总是 8, 16, 32 bit 的,虽然标准没这么规定。
=, +, -, *, /, %, ++, --, +=, -=, *=, /=, ?:
) 以及优先级
f1() + f2() + f3()
等效于 (f1() + f2()) + f3()
,但是三个函数被调用的顺序是没有定义的。
%
的定义使 (m / n) * n + m % n == m
成立。
&
, |
, ^
, ~
, <<
,>>
)
printf, cout
)
if
, else if
, else
)
for(;;)
, while
,do while
,break
,continue
)
goto
,label:
几乎不使用。
inline
函数,static
变量,pass by value/reference)
const
#include <>
和 ""
的区别
typedef
new
, delete
。
throw
, try
, catch
,std::runtime_error
,out_of_range
等。
static_cast<新类型>(变量)
和 (新类型)变量
效果相同,但有一些转换不允许。
reinterpret_cast<新类型*>(变量指针)
和 reinterpret_cast<新类型&>(变量)
并不会检查 strict aliasing rule,需要用户自己保证。
char*
和 (un)signed char*
指向任何地址,用 base type 的指针指向对象等。
cmath
complex
vector
(包括内存管理机制、改变长度可能使指针失效)
string
, u32string
iostream
(cin
,cout
,<<
算符,>>
算符,cin
可以放在判断语句中,如 if (cin >> a)
。)
ifstream
,ofstream
cin
或 fin
读到了文件末尾(文件末尾允许任意多空格/空行)?不要用 cin.eof
判断,例如读 int,可以先初始化为 INT_MAX
,然后读完以后判断是否仍为 INT_MAX
。
cin.ignore(numeric_limits<int>::max(), '\n');
#include <climits>
中的常数(INT_MIN
,INT_MAX
,DBL_MAX
,DBL_EPSILON
),以及 std::numeric_limits<>::max()
等。
unordered_set, set, unordered_map, map, list, dequeue, stack
等。
__cplusplus
用于检测 cpp 版本。
<bits/stdc++.h>
快速 include 所有 C 头文件和 STL 头文件。
pair
unordered_set
,set
unordered_map
,ordered_map
stack
queue
,deque
,priority_que
for(auto &e : v)
,需要定义 v.begin()
,v.end()
,iterator 需要支持 ++
,!=
,*p
。
public
, private
,数据成员,函数成员,operator+, -, *, /, (), []
)
类名() = default;
(可以有其他 constructor),没有 destructor,没有 virtual function。可以用 std::is_pod<类名>::value
来判断。
#include
, #define
, #if
, #ifdef
, #ifndef
, #else
, #endif
)
var
(变量),#var
(字符串),以及 ...##...
用于连接变量1。
#define ... do {} while(0)
避免多个语句不加花括号带来的错误。
namespace
constexpr
decltype
(double x; decltype(x) y;
)
[=] [&]
extern "C"
参考
#ifdef __cplusplus
用于判断是否在用 C++ 编译器,还可以判断版本:#if __cplusplus >= 201103L
,201402L
,201703L
1. ^ 例如 #define MYFUN1(x) x*x
,那么 MYFUN1(abcd)
就展开为 abcd*abcd
。#define MYFUN2(x) #x
,那么 MYFUN2(abcd)
就展开为 "abcd"
。#define MYFUN3(x,y) a##x##y##f
,那么 MYFUN3(bc,de)
展开为 abcdef
。注意作为宏函数自变量的宏名不会先展开,例如 #define NUM 5
,那么 MYFUN1(NUM)
先展开为 NUM*NUM
再进一步展开为 5*5
。又例如 MYFUN2(NUM)
会展开为 "NUM"
,但字符串不会作为宏进一步展开。宏函数体中双引号内的东西都不会展开,例如 #define MYFUN4(x) "x"
,那么 MYFUN4(abc)
仍然展开为 "x"