接前一篇文章:C++常用容器、函数、类集(2)
7. std::lock_guard
std::lock_guard是C++11标准库(STL)中的一个类模板,用于自动管理互斥锁(std::mutex或其派生类)的锁定和解锁。其主要目的是提供一种简便且安全的方式来保护临界区(critical sections)免受数据竞争(data race)的影响。
std::lock_guard是C++11引入的互斥锁管理工具,采用RAII(资源获取即初始化)机制,自动管理锁的加锁与解锁操作,适用于多线程环境下保护临界区资源。
核心特性
- 自动锁定与解锁:构造时自动加锁,析构时自动解锁,确保异常安全。
- 异常安全:即使临界区代码抛出异常,锁仍会在作用域结束时释放。
- 不可复制:避免多线程同时锁定同一资源,防止死锁。
代码示例:
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
std::mutex mtx;
int sharedResource = 0;
void threadFunction(int id) {
for (int i = 0; i < 10000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁
sharedResource += id;
// 当 lock 的作用域结束时,自动解锁
}
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(threadFunction, i);
}
for (auto& thread : threads) {
thread.join();
}
std::cout << "sharedResource: " << sharedResource << std::endl;
return 0;
}
8. auto
auto是C++11引入的关键字,用于自动推导变量类型,其核心作用是减少类型声明的冗余,让编译器根据初始化表达式自动确定变量类型。
基本用法
auto声明变量的类型会根据初始化表达式的类型自动推导,例如:
auto x = 42;(推导为 int) 14
auto y = 3.14;(推导为 double) 14
auto z = "Hello";(推导为 const char*)
使用场景
- 简化复杂类型声明
在模板或容器操作中避免冗长类型名。例如:
std::vector<std::unordered_map<std::string, int>> data;
auto it = data.begin(); // 无需写成 std::vector<...>::iterator
- 范围for循环
遍历容器时简化迭代代码。例如:
std::vector<int> vec = {1,2,3};
for(auto& num : vec) { num *= 2; } // 使用引用避免拷贝
- 函数返回类型推导(C++14 起)
允许函数返回值使用auto。例如:
auto add(int a, int b) { return a + b; } // 返回类型推导为 int
注意事项
- 初始化要求
使用auto的变量必须初始化,否则编译错误。例如:
auto z; // 无法推导,无法通过编译
- 作用范围
仅限局部变量,不能用于全局变量或函数参数。
9. std::make_shared
std::make_shared是C++11标准引入的一个函数模板,用于创建std::shared_ptr对象,并高效地分配和管理对象的内存。它比直接使用std::shared_ptr构造函数std::shared_ptr<T>(new T(...))具有更好的性能和异常安全性。
std::make_shared的优势
与std::shared_ptr<T>(new T(...))相比,std::make_shared主要有以下优点:
更少的内存分配
异常安全
代码更简洁
代码示例:
- 基本用法
#include <iostream>
#include <memory>
struct Foo {
int x;
Foo(int a) : x(a) { std::cout << "Foo constructor\n"; }
~Foo() { std::cout << "Foo destructor\n"; }
};
int main() {
std::shared_ptr<Foo> sp = std::make_shared<Foo>(42);
std::cout << "Foo.x = " << sp->x << std::endl;
return 0;
}
- 创建数组(C++20 及更高版本支持)
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int[]> arr = std::make_shared<int[]>(5);
for (int i = 0; i < 5; ++i)
arr[i] = i * 2;
for (int i = 0; i < 5; ++i)
std::cout << arr[i] << " ";
return 0;
}
10. std::shared_ptr
std::shared_ptr是C++11标准库(STL)中的智能指针类型,用于管理动态分配的对象。与传统指针不同,std::shared_ptr自动管理内存,并在不再使用时自动释放对象,以避免内存泄漏。它是一种共享所有权的智能指针,即可以让多个std::shared_ptr指向同一个对象,并且会记录有多少个std::shared_ptr指向该对象。
代码示例:
#include <memory>
#include <iostream>
struct Foo {
Foo() { std::cout << "Foo...\n"; }
~Foo() { std::cout << "~Foo...\n"; }
};
struct D {
void operator()(Foo* p) const {
std::cout << "Call delete from function object...\n";
delete p;
}
};
int main()
{
{
std::cout << "constructor with no managed object\n";
std::shared_ptr<Foo> sh1;
bool ok = sh1.get()==nullptr;
std::cout<<ok<<'\n';
}
// copy构造函数的话,引用计数都会增加
{
std::cout << "constructor with object\n";
std::shared_ptr<Foo> sh2(new Foo);
std::shared_ptr<Foo> sh3(sh2);
std::cout << sh2.use_count() << '\n';
std::cout << sh3.use_count() << '\n';
}
// 可以指定删除的函数,并传递给构造函数
{
std::cout << "constructor with object and deleter\n";
std::shared_ptr<Foo> sh4(new Foo, D());
std::shared_ptr<Foo> sh5(new Foo, [](auto p) {
std::cout << "Call delete from lambda...\n";
delete p;
});
}
}
输出:
constructor with no managed object
1 // shared_ptr 默认构造函数分配的是空指针
constructor with object
Foo...
2 // sh2 和sh3指向的都是同一个内存,所以他们的引用计数都是2
2
~Foo...
constructor with object and deleter
Foo...
Foo...
Call delete from lambda...
~Foo...
Call delete from function object...
~Foo..
更多内容请看下回。