C++advanced主题tutorial

LearningC++in advanced features, includingmove语义, lambda表达式, 智能指针进阶etc.

返回tutoriallist

1. move语义 and right 值引用

1.1 right 值引用

right 值引用 is C++11引入 new features, using&&符号表示, 用于引用临时object ( right 值) :

#include <iostream>
#include <string>

using namespace std;

void printValue(int& lvalue) { //  left 值引用parameter
    cout << " left 值引用: " << lvalue << endl;
}

void printValue(int&& rvalue) { //  right 值引用parameter
    cout << " right 值引用: " << rvalue << endl;
}

int main() {
    int x = 10; // x is  left 值
    printValue(x); // 调用 left 值引用version
    
    printValue(20); // 调用 right 值引用version
    printValue(x + 5); // 调用 right 值引用version
    
    return 0;
}

1.2 moveconstructfunction and move赋值运算符

moveconstructfunction and move赋值运算符用于将resource from 一个object转移 to 另一个object, 避免不必要 copy:

#include <iostream>
#include <string>

using namespace std;

class MyString {
private:
    char* data;
    size_t length;
public:
    // constructfunction
    MyString(const char* str) {
        length = strlen(str);
        data = new char[length + 1];
        strcpy(data, str);
        cout << "constructfunction: " << data << endl;
    }
    
    // 析构function
    ~MyString() {
        if (data) {
            cout << "析构function: " << data << endl;
            delete[] data;
        }
    }
    
    // 拷贝constructfunction
    MyString(const MyString& other) {
        length = other.length;
        data = new char[length + 1];
        strcpy(data, other.data);
        cout << "拷贝constructfunction: " << data << endl;
    }
    
    // moveconstructfunction
    MyString(MyString&& other) noexcept {
        length = other.length;
        data = other.data; // 直接接管resource
        other.data = nullptr; // 防止原object析构时释放resource
        cout << "moveconstructfunction: " << data << endl;
    }
    
    // 拷贝赋值运算符
    MyString& operator=(const MyString& other) {
        if (this != &other) {
            delete[] data;
            length = other.length;
            data = new char[length + 1];
            strcpy(data, other.data);
            cout << "拷贝赋值运算符: " << data << endl;
        }
        return *this;
    }
    
    // move赋值运算符
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            delete[] data;
            length = other.length;
            data = other.data; // 直接接管resource
            other.data = nullptr; // 防止原object析构时释放resource
            cout << "move赋值运算符: " << data << endl;
        }
        return *this;
    }
    
    const char* c_str() const {
        return data;
    }
};

MyString createString() {
    return MyString("Hello, World!"); // 返回临时object
}

int main() {
    cout << "=== creations1 ===" << endl;
    MyString s1("Hello");
    
    cout << "\n=== 拷贝constructs2 ===" << endl;
    MyString s2 = s1; // 调用拷贝constructfunction
    
    cout << "\n=== moveconstructs3 ===" << endl;
    MyString s3 = createString(); // 调用moveconstructfunction
    
    cout << "\n=== move赋值s4 ===" << endl;
    MyString s4("Initial");
    s4 = createString(); // 调用move赋值运算符
    
    cout << "\n=== 程序结束 ===" << endl;
    return 0;
}

1.3 std::movefunction

std::movefunction用于将 left 值转换 for right 值引用, from 而可以调用moveconstructfunction or move赋值运算符:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s1 = "Hello, World!";
    cout << "s1: " << s1 << endl;
    
    // usingstd::move将s1转换 for  right 值引用
    string s2 = move(s1);
    cout << "s2: " << s2 << endl;
    cout << "s1: " << s1 << endl; // s1现 in  for 空
    
    return 0;
}

2. Lambda表达式深入

2.1 Lambda表达式 语法

Lambda表达式 basic语法:

[捕获list](parameterlist) mutable -> 返回class型 { function体 }

2.1.1 捕获list

  • []: 不捕获任何variable
  • [=]: 以值方式捕获所 has out 部variable
  • [&]: 以引用方式捕获所 has out 部variable
  • [x]: 以值方式捕获x
  • [&x]: 以引用方式捕获x
  • [=, &x]: 以值方式捕获所 has out 部variable, 以引用方式捕获x
  • [this]: 捕获当 before object this指针

2.1.2 Lambda表达式 using

#include <iostream>
#include <vector>
#include <algorithms>

using namespace std;

int main() {
    vector numbers = {5, 2, 8, 1, 9, 3};
    
    // usinglambda表达式sort
    sort(numbers.begin(), numbers.end(), [](int a, int b) {
        return a > b; // 降序sort
    });
    
    // usinglambda表达式遍历
    for_each(numbers.begin(), numbers.end(), [](int n) {
        cout << n << " ";
    });
    cout << endl;
    
    // 捕获 out 部variable
    int threshold = 5;
    vector filtered;
    copy_if(numbers.begin(), numbers.end(), back_inserter(filtered), 
            [threshold](int n) {
                return n > threshold;
            });
    
    cout << " big 于" << threshold << " 数: ";
    for (int n : filtered) {
        cout << n << " ";
    }
    cout << endl;
    
    return 0;
}

2.2 Lambda表达式 class型

Lambda表达式 class型 is 编译器生成 匿名class型, 它可以转换 for function指针 or store in std::functionin:

#include <iostream>
#include <functional>

using namespace std;

int main() {
    // storelambda表达式 to std::function
    function add = [](int a, int b) {
        return a + b;
    };
    
    cout << "3 + 5 = " << add(3, 5) << endl;
    
    // serving asreturn value
    auto createMultiplier(int factor) {
        return [factor](int x) {
            return x * factor;
        };
    }
    
    auto multiplyBy2 = createMultiplier(2);
    cout << "5 * 2 = " << multiplyBy2(5) << endl;
    
    return 0;
}

3. 智能指针进阶

3.1 std::make_unique and std::make_shared

C++14引入了std::make_unique and std::make_sharedfunction, 用于security地creation智能指针:

#include <iostream>
#include <memory>

using namespace std;

class Person {
private:
    string name;
public:
    Person(const string& n) : name(n) {
        cout << "Personconstructfunction: " << name << endl;
    }
    ~Person() {
        cout << "Person析构function: " << name << endl;
    }
    void sayHello() {
        cout << "Hello, I'm " << name << endl;
    }
};

int main() {
    // usingmake_uniquecreationunique_ptr
    unique_ptr p1 = make_unique("张三");
    p1->sayHello();
    
    // usingmake_sharedcreationshared_ptr
    shared_ptr p2 = make_shared("李四");
    p2->sayHello();
    
    return 0;
}

3.2 自定义delete器

可以 for 智能指针指定自定义delete器, 用于特殊 resourcemanagement:

#include <iostream>
#include <memory>

using namespace std;

// 自定义delete器
void customDeleter(int* p) {
    cout << "自定义delete器: 释放memory" << endl;
    delete p;
}

int main() {
    // usingfunctionserving asdelete器
    unique_ptr p1(new int(10), customDeleter);
    cout << "p1 值: " << *p1 << endl;
    
    // usinglambda表达式serving asdelete器
    auto deleter = [](int* p) {
        cout << "Lambdadelete器: 释放memory" << endl;
        delete p;
    };
    unique_ptr p2(new int(20), deleter);
    cout << "p2 值: " << *p2 << endl;
    
    return 0;
}

4. constexpr and 编译期计算

4.1 constexprvariable

constexpr关键字用于声明 in 编译期计算 常量:

#include <iostream>

using namespace std;

int main() {
    constexpr int maxSize = 100;
    int arr[maxSize]; // 编译期确定 big  small 
    
    constexpr double pi = 3.14159;
    constexpr double radius = 5.0;
    constexpr double area = pi * radius * radius;
    
    cout << "圆 面积: " << area << endl;
    
    return 0;
}

4.2 constexprfunction

constexprfunction可以 in 编译期计算其return value:

#include <iostream>

using namespace std;

// constexprfunction
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

int main() {
    // 编译期计算
    constexpr int fact5 = factorial(5);
    cout << "5! = " << fact5 << endl;
    
    // run期计算
    int n;
    cout << "输入一个数: ";
    cin >> n;
    int factN = factorial(n);
    cout << n << "! = " << factN << endl;
    
    return 0;
}

5. C++11/14/17/20 new features

5.1 范围-based for循环

C++11引入了范围-based for循环, 简化了containers 遍历:

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

using namespace std;

int main() {
    vector fruits = {"苹果", "香蕉", "橙子", "葡萄"};
    
    // 范围-based for循环
    for (const auto& fruit : fruits) {
        cout << fruit << " ";
    }
    cout << endl;
    
    // modify元素
    vector numbers = {1, 2, 3, 4, 5};
    for (auto& num : numbers) {
        num *= 2;
    }
    
    for (const auto& num : numbers) {
        cout << num << " ";
    }
    cout << endl;
    
    return 0;
}

5.2 强class型枚举

C++11引入了强class型枚举, 避免了传统枚举 作用域issues:

#include <iostream>

using namespace std;

// 传统枚举
enum Color {
    RED, GREEN, BLUE
};

// 强class型枚举
enum class Fruit {
    APPLE, BANANA, ORANGE
};

enum class Vehicle {
    CAR, BUS, TRUCK
};

int main() {
    // 传统枚举
    Color c = RED;
    cout << "传统枚举值: " << c << endl;
    
    // 强class型枚举
    Fruit f = Fruit::APPLE;
    Vehicle v = Vehicle::CAR;
    
    // 强class型枚举需要显式转换 for 整型
    cout << "强class型枚举值: " << static_cast(f) << endl;
    cout << "强class型枚举值: " << static_cast(v) << endl;
    
    return 0;
}

5.3 override and final关键字

C++11引入了override and final关键字, 用于明确虚function 覆盖 and 防止inheritance:

#include <iostream>

using namespace std;

class Base {
public:
    virtual void foo() {
        cout << "Base::foo()" << endl;
    }
    
    // 防止forkclass覆盖此function
    virtual void bar() final {
        cout << "Base::bar()" << endl;
    }
};

class Derived : public Base {
public:
    // 明确表示覆盖基class 虚function
    void foo() override {
        cout << "Derived::foo()" << endl;
    }
    
    // error: 不能覆盖finalfunction
    // void bar() override {
    //     cout << "Derived::bar()" << endl;
    // }
};

// 防止被inheritance
class FinalClass final {
public:
    void func() {
        cout << "FinalClass::func()" << endl;
    }
};

// error: 不能inheritancefinalclass
// class DerivedFromFinal : public FinalClass {
// };

int main() {
    Base* b = new Derived();
    b->foo();
    b->bar();
    delete b;
    
    return 0;
}

5.4 structure化绑定 (C++17)

C++17引入了structure化绑定, 用于同时声明 many 个variable并 from 复合class型in提取值:

#include <iostream>
#include <tuple>
#include <map>

using namespace std;

int main() {
    //  from tuplein提取值
    auto person = make_tuple("张三", 25, 85.5);
    auto [name, age, score] = person;
    cout << "姓名: " << name << ", 年龄: " << age << ", 分数: " << score << endl;
    
    //  from pairin提取值
    pair product = {"苹果", 5};
    auto [productName, price] = product;
    cout << "商品: " << productName << ", 价格: " << price << endl;
    
    //  from mapin提取值
    map scores = {
        {"张三", 95},
        {"李四", 88},
        {"王五", 92}
    };
    
    for (const auto& [student, score] : scores) {
        cout << student << ": " << score << endl;
    }
    
    return 0;
}

5.5 fold表达式 (C++17)

C++17引入了fold表达式, 用于简化可变parameter模板 implementation:

#include <iostream>

using namespace std;

// fold表达式implementation求 and 
template
auto sum(Args... args) {
    return (args + ...);
}

// fold表达式implementation打印
template
void print(Args... args) {
    (cout << ... << args) << endl;
}

int main() {
    cout << "sum(1, 2, 3, 4, 5) = " << sum(1, 2, 3, 4, 5) << endl;
    
    print("Hello", " ", "World", "!");
    
    return 0;
}

实践case: implementation一个threadsecurity singleton pattern

writing一个C++程序, using现代C++featuresimplementation一个threadsecurity singleton pattern.

requirementsanalysis

  • implementation一个单例class, 确保全局只 has 一个instance.
  • 保证threadsecurity, many threadenvironment under 也能正确工作.
  • using现代C++features, such as智能指针, lambda表达式etc..
  • providing获取instance 静态method.

referencecode

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

using namespace std;

class Singleton {
private:
    string data;
    
    // 私 has constructfunction
    Singleton(const string& d) : data(d) {
        cout << "Singletonconstructfunction" << endl;
    }
    
    // 私 has 析构function
    ~Singleton() {
        cout << "Singleton析构function" << endl;
    }
    
public:
    // 禁止拷贝 and move
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;
    
    // 获取instance 静态method
    static Singleton& getInstance(const string& data = "默认值") {
        // 局部静态variableimplementation单例 (C++11 after threadsecurity) 
        static Singleton instance(data);
        return instance;
    }
    
    // 业务method
    void setData(const string& d) {
        data = d;
    }
    
    string getData() const {
        return data;
    }
    
    void showMessage() {
        cout << "Singletondata: " << data << endl;
    }
};

// testfunction
void testSingleton(int id) {
    cout << "thread" << id << "开始" << endl;
    
    // 获取单例instance
    Singleton& s = Singleton::getInstance("thread" + to_string(id) + " data");
    s.showMessage();
    
    // modifydata
    s.setData("thread" + to_string(id) + "modify after  data");
    s.showMessage();
    
    cout << "thread" << id << "结束" << endl;
}

int main() {
    cout << "主thread开始" << endl;
    
    // 主thread获取instance
    Singleton& s = Singleton::getInstance("主threaddata");
    s.showMessage();
    
    // creation many 个threadtest
    thread t1(testSingleton, 1);
    thread t2(testSingleton, 2);
    thread t3(testSingleton, 3);
    
    // etc.待thread结束
    t1.join();
    t2.join();
    t3.join();
    
    // 主thread再次获取instance
    cout << "\n主thread再次获取instance" << endl;
    Singleton& s2 = Singleton::getInstance();
    s2.showMessage();
    
    cout << "主thread结束" << endl;
    return 0;
}

run结果

主thread开始
Singletonconstructfunction
Singletondata: 主threaddata
thread1开始
Singletondata: 主threaddata
Singletondata: thread1modify after  data
thread1结束
thread2开始
Singletondata: thread1modify after  data
Singletondata: thread2modify after  data
thread2结束
thread3开始
Singletondata: thread2modify after  data
Singletondata: thread3modify after  data
thread3结束

主thread再次获取instance
Singletondata: thread3modify after  data
主thread结束
Singleton析构function

互动练习

练习1: writing一个C++程序, usingmove语义 and right 值引用implementation一个 high 效 stringclass, supportmoveconstruct and move赋值.

练习2: writing一个C++程序, usinglambda表达式 and STLalgorithmsimplementation以 under functions:

  • filter出 vector in big 于 10 元素
  • 将filter after 元素乘以 2
  • 计算processing after 元素 总 and

练习3: writing一个C++程序, using constexpr implementation编译期计算斐波那契数列 第 n 项.

练习4: writing一个C++程序, usingstructure化绑定 (C++17) 遍历一个 map, 并打印出所 has 键值 for .