摘自《C++ 17 入门经典》。几乎不会再更新。
int a = 1.1;
int b(1.2);
int c{ 1.3 }; // WRONG
使用花括号初始化变量的特点有两个:
使用花括号进行初始化时,若想要让默认值为 0,可以省略 0。
int a = 0;
int b(0);
int func(); // a function here!
int c{}; // 0 by default, OK!
注意在使用圆括号进行初始化时并不能省略这个 0,否则这表示的将会是一个函数。
auto a{ 1'0'0'0'0000'0000 };
auto a{ 0b1011 }, b{ 0B1011 };
size_t
类型sizeof
运算符得到的结果是一个 size_t
类型的整数,size_t
的宽度取决于目标平台。size_t
是无符号的。
一般而言,size_t
可以直接被使用。它还在 cstddef
头文件中被定义。
有关它们的运算法则,可以在需要时进行测试或查阅。
可以使用 cmath
中的 std::isinf()
函数和 std::isnan()
函数判断一个浮点数是否是 NaN 或者 infinity。
int a{ static_cast<int>(1.1) };
使用 limits
头文件中的 numeric_limits
类获取我们需要的值。
constexpr auto a = std::numeric_limits<int>::min();
constexpr auto b = std::numeric_limits<int>::max();
constexpr auto c = std::numeric_limits<double>::min();
constexpr auto d = std::numeric_limits<double>::max();
constexpr auto e = std::numeric_limits<double>::lowest();
cout
和 wcout
是否使用宽字符输出,取决于第一个输出操作是使用的 cout
还是 wcout
。
auto
与 std::initializer_list
仅在 cpp 17 中满足下列规则:
auto a{ 1 }; // int
auto b = { 1 }; // std::initializer_list
auto c = { 1, 2 }; // std::initializer_list
auto d{ 1, 2 }; // WRONG!
int
,不会是 short
int main()
{
enum OldOne
{
ichi,
ni,
sann
};
OldOne a = OldOne::ichi;
a = static_cast<OldOne>(2);
a = sann;
enum class NewOne
{
ICHI = 1,
NI,
SANN
};
NewOne b = NewOne::ICHI;
b = static_cast<NewOne>(2);
b = SANN; // WRONG
return 0;
}
switch
定义变量的限制在 switch
中,如果变量被定义的同时被初始化,就不能绕过变量的定义而进入变量的作用域。
switch (0)
{
case 1:
int a{ 1 };
default:
break;
}
以上代码中,在 default
后面是可以访问变量 a
,即在作用域范围内,但是在进入 default
时,变量 a
并没有被初始化,这是不允许的。
if
和 switch
语句的初始化if (int i{ 1 }; i <= 10);
switch (int i{ 1 }; i);
std::array
代替普通数组需要包含 array
头文件。
std::size
获取数组的大小支持普通数组和 array
。
auto*
如果要用指针初始化一个变量,建议使用 auto*
而非 auto
,因为在使用 auto*
时,若给定值不是一个指针,编译将不会通过。
const
在类型前,指向常量的指针,即指针可以指向别处,但修改不了被指向的地方。
const
在星号后,常量指针,即指针本身不可指向别处,但可以修改被指向的地方。
new[]
在使用类似于 new int[3] { 0, 1, 2 }
的代码时,不能省略表示大小的 3
。
int main()
{
auto a{ new int[3][4] {} };
int(*b)[4]{ new int[3][4] {} }; // note (*b)
delete[] a;
delete[] b;
}
只有第一维能够是动态的,后面的维度必须是 constexpr
的。
memory
头文件unique_ptr
该对象储存唯一的地址,并且这个地址被该对象独占。释放该对象时,其对应的指针也会释放。
std::unique_ptr<int> p{ new int {233} };
std::make_unique
auto p{ std::make_unique<int>(666) };
std::unique_ptr<int[]> p{ std::make_unique<int[]>(10) };
p[0] = 1;
get
方法使用 get
方法能够获得智能指针包含的地址。使用 get
函数,务必保证不会长时间保存得到的指针。
reset
方法reset
方法可以修改智能指针指向的值,并且在此之前对已有的指针进行删除操作。
auto p{ std::make_unique<int>(233) };
p.reset(new int{ 666 });
release
方法使用 release
方法可以将已经存在的指针宣布由自己管理,智能指针不再插手,将被设为指向 nullptr
。
auto p{ std::make_unique<int>(233) };
auto* t = p.release();
delete t;
share_ptr
share_ptr
在内部对同一个地址有一个引用计数。与 unique_ptr
不同的是,可以用一个 share_ptr
对另一个 share_ptr
进行赋值。
share_ptr
没有 release
方法和 get
方法,其他内容大同小异。
std::string::data
方法在 cpp 17,data
方法将返回一个非 const
的指针,而在之前的标准中得到的指针是 const
的。
std::string
字面量首先使用 using namespace std::string_literals;
,然后在字符串字面量后面加上后缀 s
,就能得到一个 std::string
对象。
using namespace std::string_literals;
"literal"s;
std::to_string
函数该函数能将基本类型转换为 std::string
。
std::stoi
函数该系列函数将 std::string
转换为数字。
LR"(Row)"; // ( 和 ) 别省略
R"(row)";