C++ 17 新特性、C++ 高级特性与 C++ 细节

C++ 17 新特性、C++ 高级特性与 C++ 细节

使用花括号初始化变量
代码:三种初始化变量的方式
int a = 1.1;
int b(1.2);
int c{ 1.3 }; // WRONG

使用花括号初始化变量的特点有两个:

  1. 允许以相同的方式初始化所有变量,这一点我们之后再进行进一步的讨论;
  2. 当发生收缩转换时,编译器将会报错而非警告。
零初始化

使用花括号进行初始化时,若想要让默认值为 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 头文件中被定义。

浮点数的特殊情况:NaN(Not a Number)和 infinity

有关它们的运算法则,可以在需要时进行测试或查阅。

可以使用 cmath 中的 std::isinf() 函数和 std::isnan() 函数判断一个浮点数是否是 NaN 或者 infinity。

显式类型转换
代码:显式类型转换
int a{ static_cast<int>(1.1) };
获得数值的上下界

使用 limits 头文件中的 numeric_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();
不要混合使用 coutwcout

是否使用宽字符输出,取决于第一个输出操作是使用的 cout 还是 wcout

autostd::initializer_list

仅在 C++ 17 中满足下列规则:

auto a{ 1 }; // int
auto b = { 1 }; // std::initializer_list<int>
auto c = { 1, 2 }; // std::initializer_list<int>
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
switch (0)
{
case 1:
	int a{ 1 };
default:
	break;
}

以上代码中,在 default 后面是可以访问变量 a,即在作用域范围内,但是在进入 default 时,变量 a 并没有被初始化,这是不允许的。

ifswitch 语句的初始化
代码:如果我是 for
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

指向数组的指针
代码:奇怪的 new
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<T>

该对象储存唯一的地址,并且这个地址被该对象独占。释放该对象时,其对应的指针也会释放。

代码:unique_ptr
std::unique_ptr<int> p{ new int {233} };
使用 std::make_unique<T>
代码: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 方法可以修改智能指针指向的值,并且在此之前对已有的指针进行删除操作。

代码:reset 方法
auto p{ std::make_unique<int>(233) };
p.reset(new int{ 666 });
release 方法

使用 release 方法可以将已经存在的指针宣布由自己管理,智能指针不再插手,将被设为指向 nullptr

代码:release 方法
auto p{ std::make_unique<int>(233) };
auto* t = p.release();
delete t;
share_ptr<T>

share_ptr 在内部对同一个地址有一个引用计数。与 unique_ptr 不同的是,可以用一个 share_ptr 对另一个 share_ptr 进行赋值。

share_ptr 没有 release 方法和 get 方法,其他内容大同小异。

std::string::data 方法

在 C++ 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";
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页