C++ 标准模板库(STL)提供了强大的容器、迭代器和算法,能够帮助开发者编写高效、可重用的代码。在基础使用之上,STL 还提供了一些高级用法,使得我们可以编写出更灵活和高效的代码。以下是一些 STL 的高级使用技巧和方法。
1. STL 容器的自定义比较函数
在 STL 的有序容器中(如 std::set
、std::map
),可以通过自定义比较函数来定义容器的排序规则。
示例:自定义 std::set
的比较规则
#include <iostream>
#include <set>
// 自定义比较函数,按绝对值大小排序
struct Compare {
bool operator()(int a, int b) const {
return abs(a) < abs(b);
}
};
int main() {
std::set<int, Compare> s = { -3, 2, -1, 5, -4 };
for (const auto& elem : s) {
std::cout << elem << " "; // 输出: -1 2 -3 -4 5
}
return 0;
}
2. Lambda 表达式与 STL 算法结合
C++11 引入了 Lambda 表达式,使得我们可以更加灵活地将自定义的逻辑嵌入到 STL 算法中,如 std::sort
、std::find_if
等。
示例:使用 Lambda 表达式自定义排序
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = { 5, 3, 1, 4, 2 };
// 按绝对值降序排序
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return abs(a) > abs(b);
});
for (int i : vec) {
std::cout << i << " "; // 输出: 5 4 3 2 1
}
return 0;
}
示例:使用 Lambda 表达式查找特定元素
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = { 1, 2, 3, 4, 5 };
// 查找第一个大于 3 的元素
auto it = std::find_if(vec.begin(), vec.end(), [](int x) {
return x > 3;
});
if (it != vec.end()) {
std::cout << "First element greater than 3: " << *it << std::endl; // 输出: 4
}
return 0;
}
3. 使用 std::transform
进行元素变换
std::transform
是 STL 中的一个强大算法,用于将一组元素转换为另一组元素。可以使用 Lambda 表达式或函数指针来定义转换规则。
示例:对容器中的每个元素进行平方
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = { 1, 2, 3, 4, 5 };
std::vector<int> result(vec.size());
// 对每个元素平方
std::transform(vec.begin(), vec.end(), result.begin(), [](int x) {
return x * x;
});
for (int i : result) {
std::cout << i << " "; // 输出: 1 4 9 16 25
}
return 0;
}
4. 使用 std::accumulate
进行聚合操作
std::accumulate
是一个很有用的算法,用于对容器中的元素进行聚合操作,例如求和、求积或自定义聚合。
示例:使用 std::accumulate
求和
#include <iostream>
#include <vector>
#include <numeric>
int main() {
std::vector<int> vec = { 1, 2, 3, 4, 5 };
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::cout << "Sum: " << sum << std::endl; // 输出: 15
return 0;
}
示例:使用 std::accumulate
进行字符串连接
#include <iostream>
#include <vector>
#include <numeric>
#include <string>
int main() {
std::vector<std::string> words = { "Hello", "World", "!" };
std::string sentence = std::accumulate(words.begin(), words.end(), std::string(""),
[](const std::string& a, const std::string& b) {
return a + (a.length() > 0 ? " " : "") + b;
});
std::cout << "Sentence: " << sentence << std::endl; // 输出: Hello World !
return 0;
}
5. 使用 std::copy
和 std::copy_if
进行容器拷贝
std::copy
用于将容器的元素拷贝到另一个容器,而 std::copy_if
则可以根据条件拷贝部分元素。
示例:使用 std::copy_if
复制符合条件的元素
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = { 1, 2, 3, 4, 5 };
std::vector<int> result;
// 复制所有大于 3 的元素
std::copy_if(vec.begin(), vec.end(), std::back_inserter(result), [](int x) {
return x > 3;
});
for (int i : result) {
std::cout << i << " "; // 输出: 4 5
}
return 0;
}
6. 使用 std::partition
和 std::stable_partition
进行容器分割
std::partition
可以将容器中的元素按某个条件进行分割,使得符合条件的元素排列在前,不符合条件的元素排列在后。
示例:将偶数和奇数分开
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = { 1, 2, 3, 4, 5 };
// 将偶数放在前面,奇数放在后面
std::partition(vec.begin(), vec.end(), [](int x) {
return x % 2 == 0;
});
for (int i : vec) {
std::cout << i << " "; // 输出: 2 4 3 1 5 (偶数在前)
}
return 0;
}
7. 使用 std::unique
删除容器中的重复元素
std::unique
用于消除相邻的重复元素,常与 std::sort
结合使用以删除非相邻的重复元素。
示例:删除相邻的重复元素
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = { 1, 1, 2, 2, 3, 3, 4, 4 };
auto it = std::unique(vec.begin(), vec.end());
vec.erase(it, vec.end());
for (int i : vec) {
std::cout << i << " "; // 输出: 1 2 3 4
}
return 0;
}
8. 使用 std::lower_bound
和 std::upper_bound
查找有序容器中的范围
std::lower_bound
:返回第一个不小于给定值的元素的位置。std::upper_bound
:返回第一个大于给定值的元素的位置。
示例:查找有序数组中的范围
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = { 1, 2, 4, 4, 4, 5, 6 };
auto lower = std::lower_bound(vec.begin(), vec.end(), 4);
auto upper = std::upper_bound(vec.begin(), vec.end(), 4);
std::cout << "Lower bound for 4: " << (lower - vec.begin()) << std::endl; // 输出: 2
std::cout << "Upper bound for 4: " << (upper - vec.begin()) << std::endl; // 输出: 5
return 0;
}
9. 智能指针与 STL 结合
STL 容器可以与智能指针很好地结合使用,从而避免手动管理内存。例如,使用 std::shared_ptr
或 std::unique_ptr
存储对象,容器会自动处理对象的生命周期。
示例:std::vector
中使用 std::shared_ptr
#include <iostream>
#include <memory>
#include <vector>
class Foo {
public:
Foo(int value) : value_(value) {
std::cout << "Constructing Foo(" << value_ << ")" << std::endl;
}
~Foo() {
std::cout << "Destructing Foo(" << value_ << ")" << std::endl;
}
int getValue() const { return value_; }
private:
int value_;
};
int main() {
std::vector<std::shared_ptr<Foo>> vec;
vec.push_back(std::make_shared<Foo>(1));
vec.push_back(std::make_shared<Foo>(2));
vec.push_back(std::make_shared<Foo>(3));
for (const auto& fooPtr : vec) {
std::cout << "Foo value: " << fooPtr->getValue() << std::endl;
}
return 0;
}
在这个例子中,std::shared_ptr
自动管理了 Foo
对象的生命周期,容器销毁时对象也会被正确释放。
10. 高效的哈希容器
C++11 引入了 std::unordered_set
和 std::unordered_map
,它们是基于哈希表的容器,提供了 O(1) 平均时间复杂度的查找、插入和删除操作。
示例:std::unordered_map
的使用
#include <iostream>
#include <unordered_map>
#include <string>
int main() {
std::unordered_map<std::string, int> umap;
umap["apple"] = 5;
umap["banana"] = 2;
umap["orange"] = 4;
// 遍历 unordered_map
for (const auto& pair : umap) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
// 查找元素
if (umap.find("banana") != umap.end()) {
std::cout << "Found banana, quantity: " << umap["banana"] << std::endl;
}
return 0;
}
11. 并行算法(C++17)
C++17 引入了并行 STL 算法,通过添加并行执行策略可以利用多核处理器并行执行算法。std::sort
等常见算法可以通过并行执行策略显著加速。
示例:并行 std::sort
#include <iostream>
#include <vector>
#include <algorithm>
#include <execution> // C++17 并行执行策略
int main() {
std::vector<int> vec = {5, 3, 1, 4, 2};
// 使用并行执行策略排序
std::sort(std::execution::par, vec.begin(), vec.end());
for (int i : vec) {
std::cout << i << " "; // 输出: 1 2 3 4 5
}
return 0;
}
12. 使用 std::tuple
存储多种类型
std::tuple
是 C++11 引入的一种可以存储多个不同类型对象的容器,非常适合函数返回多个值或需要存储多种类型的数据。
示例:使用 std::tuple
返回多个值
#include <iostream>
#include <tuple>
std::tuple<int, double, std::string> getValues() {
return std::make_tuple(42, 3.14, "Hello");
}
int main() {
auto [i, d, s] = getValues(); // C++17 解构绑定
std::cout << "Integer: " << i << ", Double: " << d << ", String: " << s << std::endl;
return 0;
}
在这个例子中,std::tuple
用于返回多个不同类型的值,并通过 C++17 的结构化绑定直接解构返回值。
13. std::optional
处理可能不存在的值
C++17 引入了 std::optional
,用于表示一个值可能存在或不存在。这在处理函数返回值或处理空值时非常有用。
示例:使用 std::optional
#include <iostream>
#include <optional>
std::optional<int> getValue(bool condition) {
if (condition) {
return 42;
} else {
return std::nullopt; // 表示没有值
}
}
int main() {
auto value = getValue(true);
if (value) {
std::cout << "Value: " << *value << std::endl;
} else {
std::cout << "No value" << std::endl;
}
return 0;
}