MST

星途 面试题库

面试题:C++ Lambda表达式捕获列表在复杂场景下的应用

假设有一个函数 `void processVector(std::vector<int>& vec, const std::function<void(int&)>& func)`,该函数接收一个整数向量和一个可调用对象。请使用Lambda表达式作为可调用对象传递给 `processVector`,要求Lambda捕获外部的一个 `std::map<int, int>` 变量 `mapping`,在处理向量元素时,如果向量中的元素 `i` 在 `mapping` 中有对应的值,则将向量中的元素替换为 `mapping[i]`。请详细解释这种捕获场景下可能出现的生命周期问题及如何避免。
38.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 使用Lambda表达式调用 processVector:
#include <iostream>
#include <vector>
#include <map>
#include <functional>

void processVector(std::vector<int>& vec, const std::function<void(int&)>& func) {
    for (auto& num : vec) {
        func(num);
    }
}

int main() {
    std::map<int, int> mapping = { {1, 10}, {2, 20} };
    std::vector<int> vec = {1, 2, 3};

    processVector(vec, [&mapping](int& num) {
        auto it = mapping.find(num);
        if (it != mapping.end()) {
            num = it->second;
        }
    });

    for (const auto& num : vec) {
        std::cout << num << " ";
    }
    return 0;
}
  1. 捕获场景下可能出现的生命周期问题及避免方法:
    • 生命周期问题:这里使用了引用捕获 [&mapping],这意味着Lambda表达式中的 mapping 引用的是外部作用域中的 mapping 对象。如果外部的 mapping 对象在 processVector 函数调用之前被销毁,那么Lambda表达式中对 mapping 的引用将成为悬空引用,导致未定义行为。
    • 避免方法
      • 值捕获:可以使用值捕获 [mapping],这样Lambda表达式会拷贝一份 mapping 对象,即使外部的 mapping 对象被销毁,Lambda内部的拷贝仍然有效。但这种方法可能会有性能开销,特别是当 mapping 较大时。
      processVector(vec, [mapping](int& num) {
          auto it = mapping.find(num);
          if (it != mapping.end()) {
              num = it->second;
          }
      });
      
      • 确保生命周期:确保外部 mapping 对象的生命周期长于 processVector 函数的调用周期。例如,可以将 mapping 对象定义为一个成员变量或者在一个更长生命周期的作用域内定义。如果 mapping 是在函数内部定义的局部变量,可以考虑将其定义为 static 变量,这样它的生命周期将延长到程序结束。
      static std::map<int, int> mapping = { {1, 10}, {2, 20} };
      std::vector<int> vec = {1, 2, 3};
      processVector(vec, [&mapping](int& num) {
          auto it = mapping.find(num);
          if (it != mapping.end()) {
              num = it->second;
          }
      });