为了账号安全,请及时绑定邮箱和手机立即绑定

C++11新特性入门教程

标签:
C++
概述

C++11新特性旨在提升语言的现代化程度,使C++更加简洁、高效和易用,引入了自动类型推导、范围for循环、lambda表达式等多项新功能,增强了语言的内存安全性和并发支持。

C++11 新特性简介

C++11是C++编程语言的一个重要版本,由ISO标准化组织于2011年正式发布。在此之前,C++的标准版本是C++98/03版本,已经服役了十多年,期间虽然有若干次的修订,但依然难以满足现代软件开发的需求。C++11的引入,旨在提升语言的现代化程度,使其更加简洁、高效和易用。

C++11 版本发布背景

C++11版本的发布主要基于以下几个原因:

  1. 语言的现代化:旧版本的C++语言在语法和特性上已经显得过于古老,难以满足现代软件开发的需求。C++11致力于通过引入新的语法和特性,使语言更加现代化和高效。
  2. 内存安全:旧版本的C++在内存管理方面存在一定的隐患,如堆内存泄漏和栈溢出等问题。C++11通过引入智能指针等机制,增强了语言的内存安全性。
  3. 并发支持:随着多核处理器的普及,现代软件开发越来越注重并发性能。C++11引入了thread、mutex等并发编程库,支持更高效的多线程开发。
  4. 泛型编程:C++11通过引入新的模板特性和泛型编程库(如std::function),使泛型编程更加灵活和强大。

C++11 新特性的主要特点

C++11引入了众多新特性,以下是一些主要特点:

  1. 自动类型推导(auto关键字):允许编译器自动推导变量的类型,简化了代码的编写。
  2. 范围for循环:简化了对容器的遍历操作,支持更简洁的循环结构。
  3. lambda表达式:提供了一种内联函数式编程的方式,简化了回调函数的定义。
  4. 列表初始化:引入了新的列表初始化语法,提高了代码的安全性和可读性。
  5. 移动语义和智能指针:通过移动语义和智能指针,增强了对大对象和资源的管理能力。
  6. 泛型和模板:引入了新的模板特性和泛型编程库,增强了程序的泛型能力。
  7. 并发支持:引入了thread、mutex等并发编程库,支持更高效的多线程开发。
  8. 内联变量:允许在C++代码中声明内联变量,提高了代码的灵活性和可维护性。

示例示范:自动类型推导

下面是一个使用auto关键字进行类型推导的例子:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    for (auto val : v) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    int x = 42;
    auto y = x;  // 自动推导y的类型为int
    std::cout << y << std::endl;

    auto z = 3.14;  // 自动推导z的类型为double
    std::cout << z << std::endl;

    return 0;
}

示例示范:范围for循环

下面是一个使用范围for循环的例子:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    for (int val : v) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    int sum = 0;
    for (auto val : v) {
        sum += val;
    }
    std::cout << "Sum: " << sum << std::endl;

    return 0;
}
自动类型推导与范围for循环

使用auto关键字进行类型推导

在C++11中,auto关键字可以自动推导变量的类型。这在处理容器或复杂类型时特别有用,可以简化代码并提高可读性。

示例代码:自动类型推导

#include <iostream>
#include <vector>
#include <string>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto it = v.begin();  // 自动推导it的类型为std::vector<int>::iterator
    std::cout << "First element: " << *it << std::endl;

    auto str = std::string("Hello, World!");  // 自动推导str的类型为std::string
    std::cout << "String: " << str << std::endl;

    auto num = 42;  // 自动推导num的类型为int
    std::cout << "Number: " << num << std::endl;

    auto val = 3.14;  // 自动推导val的类型为double
    std::cout << "Float: " << val << std::endl;

    return 0;
}

示例代码:范围for循环

范围for循环是C++11引入的一个新特性,用于简化对容器的遍历操作。下面是一个简单的例子:

#include <iostream>
#include <vector>
#include <string>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    for (auto val : v) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    std::vector<std::string> words = {"Hello", "World", "C++", "11"};
    for (auto word : words) {
        std::cout << word << " ";
    }
    std::cout << std::endl;

    return 0;
}

范围for循环的基本用法

范围for循环的一般语法如下:

for (auto val : container) {
    // 处理每个元素
}

其中container可以是任何支持范围for循环的容器类型,如std::vector, std::list, std::array等。

示例代码:范围for循环的使用

#include <iostream>
#include <vector>
#include <string>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    int sum = 0;
    for (auto val : v) {
        sum += val;
    }
    std::cout << "Sum: " << sum << std::endl;

    std::vector<std::string> words = {"Hello", "World", "C++", "11"};
    for (auto &word : words) {
        word += "!";
    }
    for (auto word : words) {
        std::cout << word << " ";
    }
    std::cout << std::endl;

    return 0;
}

在上面的示例中,我们使用范围for循环遍历std::vector<int>std::vector<std::string>,并进行了简单的计算和修改操作。

Lambda表达式

Lambda表达式的定义

Lambda表达式是一种匿名函数,可以在代码中直接定义和使用。它提供了一种简洁的方式来定义简单的函数,特别适用于回调函数等场景。

Lambda表达式的语法

[capture_list](parameters) -> return_type {
    // 函数体
}
  • capture_list:捕获列表,定义了lambda函数可以从其外部捕获的变量。
  • parameters:参数列表,定义了lambda函数的参数。
  • return_type:返回类型,定义了lambda函数的返回值类型。
  • 函数体:实现了lambda函数的具体逻辑。

捕获列表

捕获列表定义了lambda函数可以从其外部捕获的变量。有以下几种捕获方式:

  • &:按引用捕获,可以改变外部变量的值。
  • =:按值捕获,不能改变外部变量的值。

示例:

int x = 10;

auto lambda1 = [x]() {
    return x;
};

auto lambda2 = [&x]() {
    ++x;
    return x;
};

std::cout << "lambda1: " << lambda1() << std::endl;  // 输出10
std::cout << "lambda2: " << lambda2() << std::endl;  // 输出11

Lambda表达式的使用场景

  • 回调函数:lambda函数可以简化回调函数的定义和使用。
  • 算法函数:lambda函数可以方便地定义算法函数,如排序、查找等。
  • 辅助函数:lambda函数可以作为辅助函数,简化代码结构。

示例代码:回调函数

#include <iostream>
#include <vector>

void applyFunction(const std::vector<int>& vec, auto func) {
    for (int val : vec) {
        std::cout << func(val) << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    applyFunction(v, [](int x) { return x * 2; });  // 输出2 4 6 8 10
    applyFunction(v, [](int x) { return x + 1; });  // 输出2 3 4 5 6

    return 0;
}

示例代码:辅助函数

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};

    auto isEven = [](int x) { return x % 2 == 0; };

    for (int val : v) {
        if (isEven(val)) {
            std::cout << val << " ";
        }
    }
    std::cout << std::endl;

    return 0;
}
新的初始化方式

列表初始化

列表初始化是一种新的初始化方式,通过使用花括号{}来初始化变量。它可以自动推导类型,提高代码的可读性和安全性。

示例代码:列表初始化

#include <iostream>
#include <vector>
#include <string>

int main() {
    int x = 42;
    double y = 3.14;
    std::string str = "Hello, World!";
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::vector<std::string> words = {"Hello", "World", "C++", "11"};

    std::cout << "x: " << x << std::endl;
    std::cout << "y: " << y << std::endl;
    std::cout << "str: " << str << std::endl;
    std::cout << "v: ";
    for (int val : v) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
    std::cout << "words: ";
    for (const auto& word : words) {
        std::cout << word << " ";
    }
    std::cout << std::endl;

    return 0;
}

活动成员初始化

活动成员初始化是一种新的初始化方式,可以在类的构造函数中直接初始化成员变量。这种方式可以提高代码的安全性和可读性。

示例代码:活动成员初始化

#include <iostream>
#include <string>

class Person {
public:
    Person(std::string name, int age) : name(name), age(age) {}

    std::string getName() const { return name; }
    int getAge() const { return age; }

private:
    std::string name;
    int age;
};

int main() {
    Person p("Alice", 30);
    std::cout << "Name: " << p.getName() << std::endl;
    std::cout << "Age: " << p.getAge() << std::endl;

    return 0;
}
移动语义与智能指针

移动语义的基本概念

移动语义是一种新的资源管理机制,用于优化资源的分配和释放。它通过将资源的所有权从一个对象移动到另一个对象,避免了不必要的复制操作,提高了程序的性能。

示例代码:移动语义

#include <iostream>
#include <string>

class String {
public:
    String(const std::string& s) : data(new std::string(s)) {}
    String(String&& other) noexcept : data(other.data) {
        other.data = nullptr;
    }
    ~String() { delete data; }

    std::string* data;
};

int main() {
    String str1("Hello, World!");
    String str2 = std::move(str1);

    std::cout << "str1: " << *(str1.data) << std::endl;
    std::cout << "str2: " << *(str2.data) << std::endl;

    return 0;
}

智能指针的使用方法

智能指针是一种管理指针生命周期的工具,可以自动释放内存,避免了内存泄漏等问题。C++11提供了几种智能指针,包括std::unique_ptrstd::shared_ptrstd::weak_ptr

示例代码:智能指针

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass created" << std::endl; }
    ~MyClass() { std::cout << "MyClass destroyed" << std::endl; }
};

int main() {
    std::unique_ptr<MyClass> ptr1(new MyClass());
    {
        std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>();
        std::weak_ptr<MyClass> weakPtr = ptr2;

        std::cout << "ptr2 use_count: " << ptr2.use_count() << std::endl;

        if (auto sharedPtr = weakPtr.lock()) {
            std::cout << "weakPtr is valid" << std::endl;
        } else {
            std::cout << "weakPtr is invalid" << std::endl;
        }
    }

    // ptr2的生命周期结束,但ptr1仍然有效
    std::cout << "ptr1 is valid" << std::endl;

    return 0;
}
C++11线程支持

thread类的基本用法

在C++11中,标准库引入了std::thread类,用于支持多线程编程。下面是一些基本用法示例。

示例代码:创建和启动线程

#include <iostream>
#include <thread>

void threadFunction() {
    std::cout << "Hello from thread" << std::endl;
}

int main() {
    std::thread t(threadFunction);
    t.join();

    return 0;
}

示例代码:传递参数给线程

#include <iostream>
#include <thread>

void threadFunction(int x) {
    std::cout << "Hello from thread, x = " << x << std::endl;
}

int main() {
    std::thread t(threadFunction, 42);
    t.join();

    return 0;
}

mutex类的基本用法

在多线程编程中,std::mutex是用于保护共享资源的重要工具。它提供了一种机制,确保在同一时间只有一个线程可以访问共享资源。

示例代码:使用mutex

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;
int counter = 0;

void incrementCounter() {
    for (int i = 0; i < 10000; ++i) {
        std::lock_guard<std::mutex> guard(mtx);
        ++counter;
    }
}

int main() {
    std::thread t1(incrementCounter);
    std::thread t2(incrementCounter);

    t1.join();
    t2.join();

    std::cout << "Counter value: " << counter << std::endl;

    return 0;
}

在上面的示例中,我们创建了两个线程,并使用std::mutex来保护共享的counter变量。std::lock_guard自动锁定了mutex,并在析构时自动解锁,简化了锁的管理。

总结

C++11引入了众多新特性,极大地丰富了语言的功能并提高了代码的可读性和效率。通过了解和掌握这些新特性,可以更好地利用C++进行高效和现代的软件开发。推荐大家可以进一步学习和实践这些新特性,以提升编程技能。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消