当前位置: 首页 > news >正文

【C++】:C++11详解 —— 入门基础

目录

C++11简介

统一的列表初始化

1.初始化范围扩展

2.禁止窄化转换(Narrowing Conversion)

3.解决“最令人烦恼的解析”(Most Vexing Parse)

4.动态数组初始化

5. 直接初始化返回值

总结

声明

1.auto 类型推导

2. decltype 类型推导

3. 尾置返回类型(Trailing Return Type)

4. nullptr 关键字

5.using 别名声明

6.默认和删除函数(= default 与 = delete)

范围for循环

STL容器

1. std::array(固定大小数组)

2. std::forward_list(单向链表)

3. 无序关联容器(基于哈希表)

4. std::tuple(元组容器)


C++11简介

C++11(原称 C++0x)是 C++ 编程语言的第三个国际标准(ISO/IEC 14882:2011),于 2011 年 8 月正式发布。它是自 1998 年 C++98 标准后的首次重大更新,引入了大量新特性,旨在提高代码效率、简化开发流程并支持现代编程范式。C++11 被广泛认为是 C++ 的“现代化重生”,推动了语言向更高抽象层级、更安全的资源管理和更强大的并发支持发展。

C++11 的起源

  1. 应对现代编程挑战
    C++03(2003 年小修订版)后,开发者逐渐发现语言在并发编程、泛型编程和资源管理上的局限性。硬件多核化、移动语义需求(如高效对象转移)等趋势要求语言进化。

  2. 标准化进程

    • C++0x 项目:最初计划在 2000 年代完成(故代号 C++0x),但因复杂性多次延期,最终于 2011 年发布,更名为 C++11。

    • 委员会合作:ISO C++ 标准委员会(WG21)主导设计,融合了全球开发者、学术界和企业的提案,Bjarne Stroustrup(C++ 创始人)和 Herb Sutter 等专家推动关键特性。

  3. 设计目标

    • 保持与 C++98/C++03 的兼容性。

    • 提升类型安全性和性能(如右值引用、移动语义)。

    • 简化代码(如 auto 关键字、范围 for 循环)。

    • 支持多线程(标准线程库 <thread>)。

统一的列表初始化

C++11 引入了 统一列表初始化(Uniform Initialization),允许使用统一的 {} 语法初始化各种类型的对象(包括基本类型、数组、结构体、类对象、容器等)。这一特性解决了传统初始化方式的不一致性问题,增强了代码的可读性和安全性。

1.初始化范围扩展

C++98 的限制

  • 仅支持聚合类型(如数组、无自定义构造函数的结构体/类)的列表初始化:
int arr[] = {1, 2, 3};        // 允许:数组

struct Point 
{ 
    int x;
    int y; 
};
Point p = {3, 4};             // 允许:聚合类
  • 不支持非聚合类型(如有构造函数的类或 STL 容器)直接使用 {} 初始化:
std::vector<int> v = {1, 2, 3}; // C++98 报错:不支持直接列表初始化

C++11 的改进

  • 支持所有类型(包括非聚合类、容器、用户自定义类型)的列表初始化: 
    // 直接初始化非聚合类(需定义接受 std::initializer_list 的构造函数)
    std::vector<int> v = {1, 2, 3};   // 合法
    std::string s{"Hello"};           // 合法

    struct Point
    {
	    int _x;
	    int _y;
    };
    // 使用大括号对内置类型进行初始化
	int x1 = { 1 }; // 可添加等号
	int x2{ 2 };    // 可不添加等号

	// 使用大括号对数组元素进行初始化
	int array1[]{1, 2, 3, 4, 5}; // 可不添加等号

	// 使用大括号对结构体元素进行初始化
	Point p{ 1, 2 }; //可不添加等号

2.禁止窄化转换(Narrowing Conversion)

C++98 的问题

  • 允许隐式窄化转换(可能导致数据丢失或未定义行为):

int x = 5.5;   // 合法:隐式截断为 5(但可能导致逻辑错误)

C++11 的改进

  • 使用 {} 初始化时禁止隐式窄化转换:

int x{5.5};    // 编译错误:double → int 是窄化转换
int y(5.5);    // 合法(传统方式允许,但结果可能不符合预期)

3.解决“最令人烦恼的解析”(Most Vexing Parse)

C++98 的歧义问题

  • 声明对象时可能被误解析为函数声明:

class Widget { /*...*/ };
Widget w();     // 歧义:声明一个返回 Widget 的函数,而非默认构造对象

C++11 的改进

  • 使用 {} 消除歧义:

Widget w1{};    // 明确调用默认构造函数
Widget w2();    // 仍被解析为函数声明

4.动态数组初始化

C++98 的限制

  • 动态分配的数组无法直接初始化:

int* arr = new int[3]; // 需后续逐个赋值
arr[0] = 1; arr[1] = 2; arr[2] = 3;

C++11 的改进

  • 允许动态数组直接使用列表初始化:

int* arr = new int[3]{1, 2, 3}; // 合法

5. 直接初始化返回值

C++98 的局限

  • 函数返回复杂对象时需显式构造:

std::vector<int> getData() {
    std::vector<int> tmp;
    tmp.push_back(1);
    tmp.push_back(2);
    return tmp;
}

C++11 的改进

  • 可直接返回初始化列表:

std::vector<int> getData() {
    return {1, 2, 3}; // 直接构造并返回
}

总结

C++11 的统一列表初始化通过以下方式彻底改变了 C++ 的编码风格:

  1. 语法一致性:所有类型初始化方式统一,减少记忆负担。

  2. 安全性增强:禁止窄化转换,避免潜在错误。

  3. 代码简洁性:简化容器和复杂对象的初始化流程。

  4. 现代编程支持:为后续标准(如 C++14/17)的改进奠定基础。

声明

C++11 在变量、函数、类等声明方面引入了多项重要改进,旨在提升代码简洁性、类型安全性和表达能力。

1.auto 类型推导

  • 功能:允许编译器自动推导变量类型,减少冗余的类型书写。

auto x = 42;                    // x → int
auto s = "Hello";               // s → const char*
std::vector<int> vec = {1, 2, 3};
auto it = vec.begin();          // it → std::vector<int>::iterator

// C++98 必须显式写出类型
std::vector<int>::iterator it = vec.begin();

2. decltype 类型推导

  • 功能:获取表达式的类型,用于声明复杂类型或模板编程。

int x = 10;
decltype(x) y = 20;             // y 的类型为 int

template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) { // 推导返回值类型
    return a + b;
}

3. 尾置返回类型(Trailing Return Type)

  • 功能:将函数返回类型放在参数列表之后,提高可读性(尤其适用于模板函数)。

auto func(int a, double b) -> int; // 声明


// 结合 decltype 推导返回值类型。
// Lambda 表达式(隐式使用尾置返回类型)。
template<typename T, typename U>
auto multiply(T t, U u) -> decltype(t * u) {
    return t * u;
}

4. nullptr 关键字

  • 功能:替代 NULL 或 0 表示空指针,避免与整数类型的歧义。

void func(int);
void func(char*);
func(nullptr); // 调用 void func(char*)
func(0);       // 调用 void func(int)

// C++98
int* p = NULL; // C++98 中 NULL 通常是 0 的宏定义,类型不安全

5.using 别名声明

  • 功能:替代 typedef 定义类型别名,支持模板化。

using IntPtr = int*;          // 等价于 typedef int* IntPtr;
template<typename T>

using Vec = std::vector<T>;   // 模板化别名(C++98 无法实现)
Vec<int> v;                   // 等价于 std::vector<int>

6.默认和删除函数(= default 与 = delete

  • = default:显式要求编译器生成默认函数(如构造函数、拷贝赋值运算符)。

class MyClass {
public:
    MyClass() = default;      // 显式生成默认构造函数
};
  • = delete:禁止编译器生成特定函数,或禁用某些重载。
class NonCopyable {
public:
    NonCopyable(const NonCopyable&) = delete; // 禁止拷贝
};
void func(int) {}
void func(double) = delete;   // 禁用 double 版本的重载

范围for循环

范围 for 循环是 C++11 引入的一项简化遍历操作的特性,它允许开发者以更简洁、直观的方式遍历容器、数组或其他可迭代对象的元素。

基本语法

for (声明 : 范围表达式) 
{
    // 循环体
}
  • 声明:定义一个变量,用于依次获取范围内的每个元素(通常使用 auto 推导类型)。

  • 范围表达式:可以是数组、STL 容器(如 vectorlist)、初始化列表,或任何支持 begin() 和 end() 成员/自由函数的对象。

  • 隐式依赖 begin() 和 end()

    • 范围表达式必须能通过 begin(范围表达式) 和 end(范围表达式) 获取迭代器(包括自由函数或成员函数)。

代码示例:

// 结合 auto 关键字,避免显式写出复杂类型:
std::vector<int> vec = {1, 2, 3};
for (auto& num : vec)     // 使用引用避免拷贝
{ 
    num *= 2; // 可修改元素
}

// 使用 const auto& 避免拷贝,同时防止修改元素
for (const auto& str : stringList) 
{
    std::cout << str << std::endl;
}

STL容器

C++11中新增了五个容器,分别是array、forward_list、unordered_map和unordered_set、tuple

1. std::array(固定大小数组)

  • 用途:替代传统的 C 风格数组,提供安全的边界检查、STL 兼容接口和值语义

  • 对比 C++98:C 风格数组无成员函数,且易因越界导致未定义行为。

#include <array>
std::array<int, 3> arr = {1, 2, 3};
arr.at(1) = 42;    // 安全访问(越界抛出异常)
for (auto num : arr) { std::cout << num; } // 范围 for 循环

2. std::forward_list(单向链表)

  • 用途:内存敏感场景下的单向链表,仅支持前向遍历。

  • 特点

    • 比 std::list(双向链表)更省内存(每个节点少一个指针)。

    • 仅支持 push_front()insert_after() 等操作,无 size() 方法。

  • 适用场景:需要低内存开销且无需反向遍历的场景(如缓存池、轻量级链表)。

#include <forward_list>
std::forward_list<int> flist = {1, 2, 3};
flist.push_front(0);       // 头部插入
auto it = flist.begin();
flist.insert_after(it, 99); // 在第一个元素后插入

3. 无序关联容器(基于哈希表)

C++11 引入了基于哈希表的无序容器,提供平均 O(1) 复杂度的查找、插入和删除操作。

  • std::unordered_set 和 std::unordered_multiset

  • std::unordered_map 和 std::unordered_multimap

可以查看前面文章,STL详解

4. std::tuple(元组容器)

  • 用途:存储任意类型组合的固定大小集合(类似结构体,但无需显式定义类型)。

  • 特点

    • 支持通过 std::get<索引> 或结构化绑定(C++17)访问元素。

    • 常用于函数多返回值或泛型编程。

#include <tuple>
auto data = std::make_tuple(42, "Hello", 3.14);
int num = std::get<0>(data);      // 获取第一个元素
std::string str = std::get<1>(data); 

对比表格:C++11 新增容器 vs C++98 容器

容器类型C++11 新增C++98 类似容器主要差异
固定数组std::arrayC 风格数组安全、支持 STL 接口
单向链表std::forward_liststd::list仅前向遍历,内存更省
哈希集合std::unordered_setstd::set无序 vs 有序,哈希表 vs 红黑树
哈希映射std::unordered_mapstd::map同上
元组std::tuple(增强)无直接等价多类型混合存储

相关文章:

  • Matlab 经验模态分解和时频图绘制
  • SAP WORKFLOW BUSINESS PROCESS AUTOMATION
  • QVariant:Qt中万能类型的使用与理解
  • 重生之我在学Vue--第17天 Vue 3 项目优化与部署
  • openEuler系统迁移 Docker 数据目录到 /home,解决Docker 临时文件占用大问题
  • 鸿蒙路由 HMRouter 配置及使用 三 全局拦截器使用
  • AtCoder Beginner Contest 397 A - D题解
  • 举例说明 牛顿法 Hessian 矩阵
  • python实现简单的图片去水印工具
  • 表单引擎赋能AI:引领未来表单设计新趋势
  • 单片机外设快速入门篇(五)——GPIO篇
  • Houdini :《哪吒2》神话与科技碰撞的创新之旅
  • 【linux】虚拟机执行sudo yum isntall perl报错 could not retrieve mirrorlist htt:
  • 通向AGI的未来之路!首篇2D/视频/3D/4D统一生成框架全景综述(港科大中山等)
  • Elasticsearch使用记录
  • spring动态代理是在生命周期的哪个阶段实现的
  • 矩阵期望 E 的含义:概率
  • 蓝桥杯高频考点——进制转换
  • 【 利用socket来实现简单远控】
  • c++中字符串string常用的函数
  • 山东市监局回应“盒马一批次‘无抗’鸡蛋抽检不合格后复检合格”:系生产商自行送检
  • 沈阳卫健委通报“健康证”办理乱象:涉事医院已被立案查处
  • 习近平出席中国-拉美和加勒比国家共同体论坛第四届部长级会议开幕式并发表重要讲话
  • 2025上海科技节本周六启幕,机器人和科学家同走AI科学红毯
  • 马上评丨为护士减负,不妨破除论文“硬指标”
  • 广西百色通报:极端强对流天气致墙体倒塌,3人遇难7人受伤