BLOG

Record, summarize, and improve.

C++安全

线程安全(Thread Safety)

不安全示例

#include <iostream>
#include <thread>
int counter = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        counter++; // 多个线程同时修改共享变量,导致数据竞争
    }
}

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

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

    std::cout << "Counter: " << counter << std::endl; // 结果可能小于 200000
    return 0;
}

问题:多个线程同时修改counter,导致数据竞争,结果不确定。

线程安全改进

#include <iostream>
#include <thread>
#include <mutex>
int counter = 0;
std::mutex mtx;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(mtx); // 使用互斥锁保护共享资源
        counter++;
    }
}

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

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

    std::cout << "Counter: " << counter << std::endl; // 结果一定是 200000
    return 0;
}

改进:使用std::mutex保护共享变量,确保线程安全。

类型安全(Type Safety)

不安全示例

#include <iostream>
int main() {
    double value = 3.14;
    int* ptr = (int*)&value; // C风格强制类型转换,破坏了类型安全
    std::cout << *ptr << std::endl; // 未定义行为
    return 0;
}

问题:C风格强制类型转换可能导致未定义行为。

类型安全改进

#include <iostream>
int main() {
    double value = 3.14;
    int intValue = static_cast<int>(value); // 使用安全的类型转换
    std::cout << intValue << std::endl; // 输出 3
    return 0;
}

改进:使用static_cast进行安全的类型转换。

内存安全(Memory Safety)

不安全示例

#include <iostream>
int main() {
    int* ptr = new int(10);
    delete ptr;
    std::cout << *ptr << std::endl; // 访问已释放的内存,悬空指针
    return 0;
}

问题:访问已释放的内存,导致未定义行为。

内存安全改进

#include <iostream>
#include <memory>
int main() {
    auto ptr = std::make_unique<int>(10); // 使用智能指针管理内存
    std::cout << *ptr << std::endl; // 输出 10
    // 不需要手动释放内存,智能指针会自动释放
    return 0;
}

改进:使用std::unique_ptr管理内存,避免悬空指针。

异常安全(Exception Safety)

不安全示例

#include <iostream>
void unsafeFunction() {
    int* ptr = new int(10);
    throw std::runtime_error("Error!"); // 抛出异常
    delete ptr; // 不会执行,导致内存泄漏
}

int main() {
    try {
        unsafeFunction();
    } catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

问题:抛出异常时,资源未释放,导致内存泄漏。

异常安全改进

#include <iostream>
#include <memory>
void safeFunction() {
    auto ptr = std::make_unique<int>(10); // 使用智能指针
    throw std::runtime_error("Error!"); // 抛出异常
    // 不需要手动释放内存,智能指针会自动释放
}

int main() {
    try {
        safeFunction();
    } catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

改进:使用智能指针确保资源在异常发生时自动释放。

并发安全(Concurrency Safety)

不安全示例

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

std::mutex mtx1;
std::mutex mtx2;

void thread1() {
    std::lock_guard<std::mutex> lock1(mtx1);
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟耗时操作
    std::lock_guard<std::mutex> lock2(mtx2); // 可能导致死锁
}

void thread2() {
    std::lock_guard<std::mutex> lock2(mtx2);
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟耗时操作
    std::lock_guard<std::mutex> lock1(mtx1); // 可能导致死锁
}

int main() {
    std::thread t1(thread1);
    std::thread t2(thread2);

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

    std::cout << "Done" << std::endl;
    return 0;
}

问题:两个线程互相等待对方释放锁,导致死锁。

并发安全改进

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

std::mutex mtx1;
std::mutex mtx2;

void thread1() {
    std::lock(mtx1, mtx2); // 同时锁定多个互斥锁,避免死锁
    std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

void thread2() {
    std::lock(mtx1, mtx2); // 同时锁定多个互斥锁,避免死锁
    std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

int main() {
    std::thread t1(thread1);
    std::thread t2(thread2);

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

    std::cout << "Done" << std::endl;
    return 0;
}

改进:使用std::lock同时锁定多个互斥锁,避免死锁。

资源安全(Resource Safety)

不安全示例

#include <iostream>
#include <fstream>
void unsafeFunction() {
    std::ofstream file("test.txt");
    file << "Hello, World!" << std::endl;
    throw std::runtime_error("Error!"); // 抛出异常
    file.close(); // 不会执行,导致文件句柄泄漏
}

int main() {
    try {
        unsafeFunction();
    } catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

问题:抛出异常时,文件句柄未关闭,导致资源泄漏。

资源安全改进

#include <iostream>
#include <fstream>
void safeFunction() {
    std::ofstream file("test.txt");
    file << "Hello, World!" << std::endl;
    throw std::runtime_error("Error!"); // 抛出异常
    // 不需要手动关闭文件,RAII 会自动关闭
}

int main() {
    try {
        safeFunction();
    } catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

改进:利用RAII机制,文件在作用域结束时自动关闭。

边界安全(Bounds Safety)

不安全示例

#include <iostream>
int main() {
    int arr[3] = {1, 2, 3};
    std::cout << arr[5] << std::endl; // 越界访问,未定义行为
    return 0;
}

问题:访问数组越界,导致未定义行为。

边界安全改进

#include <iostream>
#include <vector>
int main() {
    std::vector<int> arr = {1, 2, 3};
    if (arr.size() > 5) {
        std::cout << arr[5] << std::endl; // 检查边界
    } else {
        std::cout << "Out of bounds!" << std::endl;
    }
    return 0;
}

改进:使用std::vector并检查边界,避免越界访问。