如何在std算法中使用unique_ptr的transform_iterator调用lower_bound?
解决
vector<unique_ptr<T>>结合转换迭代器调用lower_bound的问题 首先得戳破你遇到的核心误解:unique_ptr不可拷贝没错,但std::lower_bound里的迭代器赋值(比如__first = __middle)操作,赋值的是迭代器本身,不是迭代器指向的unique_ptr元素。迭代器本质是指向容器元素位置的“指针式对象”,拷贝/赋值迭代器只会改它的指向,根本碰不到unique_ptr的拷贝逻辑。你遇到的编译错误,大概率是转换迭代器的使用方式错了,或是没给lower_bound指定正确的比较规则。
错误根源拆解
常见的踩坑场景有两种:
- 自己实现的转换迭代器逻辑有问题,误在迭代器拷贝时尝试拷贝
unique_ptr; - 没给
lower_bound传自定义比较函数,编译器误以为要直接比较unique_ptr和目标double值,触发了非法的unique_ptr操作。
正确实现方案
用标准库的std::transform_iterator就能完美解决——它会自动帮你完成int→double的转换,全程不碰unique_ptr的拷贝,再配合自定义比较函数就能顺利跑通lower_bound。
完整可运行代码
#include <vector> #include <memory> #include <algorithm> #include <iterator> #include <iostream> int main() { // 初始化存储unique_ptr<int>的容器 std::vector<std::unique_ptr<int>> num_list; num_list.emplace_back(std::make_unique<int>(1)); num_list.emplace_back(std::make_unique<int>(3)); num_list.emplace_back(std::make_unique<int>(5)); num_list.emplace_back(std::make_unique<int>(7)); double target = 4.2; // 要查找的目标值 // 定义转换逻辑:把unique_ptr<int>转成double auto to_double = [](const std::unique_ptr<int>& ptr) -> double { return static_cast<double>(*ptr); }; // 创建转换迭代器,自动包装原容器迭代器 auto transform_begin = std::make_transform_iterator(num_list.begin(), to_double); auto transform_end = std::make_transform_iterator(num_list.end(), to_double); // 调用lower_bound,显式传入比较逻辑 auto found_it = std::lower_bound(transform_begin, transform_end, target, [](const decltype(*transform_begin)& converted_val, double target_val) { return converted_val < target_val; }); // 输出结果,若找到则获取原容器的迭代器 if (found_it != transform_end) { auto original_iter = found_it.base(); std::cout << "第一个大于等于" << target << "的元素是:" << **original_iter << std::endl; } else { std::cout << "没有找到符合条件的元素" << std::endl; } return 0; }
关键细节说明
std::transform_iterator的安全性:它只持有原容器的迭代器,解引用时才执行转换逻辑返回double,全程不会拷贝或移动unique_ptr;- 自定义比较函数:显式指定比较规则,避免编译器误判类型,确保比较的是转换后的
double值,而非原始的unique_ptr; - 还原原迭代器:如果需要操作原容器里的
unique_ptr,用转换迭代器的base()方法就能拿到原容器的迭代器,安全又方便。
不想用标准库迭代器?自定义极简适配器也可以
如果你想自己实现转换迭代器,核心是只持有原容器迭代器,解引用时执行转换:
template <typename Iter, typename Func> struct TransformAdapter { Iter inner_iter; Func convert_func; using value_type = decltype(convert_func(*inner_iter)); using reference = value_type; using iterator_category = typename std::iterator_traits<Iter>::iterator_category; TransformAdapter(Iter it, Func f) : inner_iter(it), convert_func(std::move(f)) {} reference operator*() const { return convert_func(*inner_iter); } TransformAdapter& operator++() { ++inner_iter; return *this; } bool operator==(const TransformAdapter& other) const { return inner_iter == other.inner_iter; } bool operator!=(const TransformAdapter& other) const { return !(*this == other); } // 若原迭代器是随机访问类型,可补充+=、-等操作 }; // 辅助函数简化创建 template <typename Iter, typename Func> auto make_transform_adapter(Iter it, Func f) { return TransformAdapter<Iter, Func>(it, std::move(f)); }
用法和标准库的transform_iterator完全一致,同样不会触发unique_ptr的非法操作。
内容的提问来源于stack exchange,提问作者Candy Chiu
相关产品推荐
相关产品推荐

