You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何std::partial_sort_copy无法填充vector容器?

问题:std::partial_sort_copy无法填充vector的原因及修复

问题描述

尝试基于自定义比较器从std::map中选取前k个元素并插入vector,使用std::partial_sort_copy实现,但运行后vector未被填充。注释掉的代码可实现预期功能,需排查错误原因。

原代码

#include <algorithm>                                                                                                                                                                                           
#include <cstdint>
#include <iostream>
#include <map>
#include <vector>

struct Values
{
        uint32_t a = 0;
        uint32_t b = 0;

        Values(uint32_t x, uint32_t y): a(x), b(y) {}
};

template <typename MapType>
auto print_top_k(std::size_t k, MapType&& map)
{
        std::vector<std::pair<typename MapType::key_type, typename MapType::mapped_type>> v;
        v.reserve(map.size());
        std::cout << v.size() << "\n";

        // std::transform(map.begin(), map.end(), std::back_inserter(v), [](const auto& kv) { return kv; });
        // std::sort(v.begin(), v.end(), [](const auto& lhs, const auto& rhs){ return lhs.second.a > rhs.second.b; }); 
        // v.erase(v.begin() + k, v.end());

        std::partial_sort_copy(map.begin(), map.end(), v.begin(), std::next(v.begin(), k), [](const auto& lhs, const auto& rhs){ return lhs.second.a > rhs.second.b; });
        std::cout << v.size() << "\n";

        std::cout << std::distance(map.begin(), map.end()) << " " << std::distance(v.begin(), std::next(v.begin(), k)) << "\n";
        for(const auto& kv: v)
            std::cout << kv.first << " -> (" << kv.second.a << ", " << kv.second.b << ")\n";
}

int main()
{
        std::map<uint32_t, Values> data;
        for(uint32_t i = 0; i < 100; i++)
            data.emplace(std::piecewise_construct, std::forward_as_tuple(i), std::forward_as_tuple(2*i, 3*i));

        print_top_k(10, std::move(data));

        return 0;
}

运行输出

0
0
100 10

错误原因及修复

核心错误

std::partial_sort_copy要求目标容器已分配足够的元素空间(即size满足需求),但你仅调用了v.reserve(map.size()):

  • reserve仅预分配内存,不会改变vector的size,此时v的size仍为0。
  • v.begin()到std::next(v.begin(),k)是非法的迭代器范围,后续操作属于未定义行为,自然无法填充元素。

修复方法

将v.reserve(map.size())替换为初始化vector的size为需要容纳的元素数量(需考虑map元素数少于k的情况):

template <typename MapType>
auto print_top_k(std::size_t k, MapType&& map)
{
        std::vector<std::pair<typename MapType::key_type, typename MapType::mapped_type>> v;
        auto target_size = std::min(k, map.size());
        v.resize(target_size); // 分配足够的元素空间,让迭代器范围有效
        std::cout << v.size() << "\n";

        std::partial_sort_copy(map.begin(), map.end(), v.begin(), v.end(), [](const auto& lhs, const auto& rhs){ return lhs.second.a > rhs.second.b; });
        std::cout << v.size() << "\n";

        std::cout << std::distance(map.begin(), map.end()) << " " << target_size << "\n";
        for(const auto& kv: v)
            std::cout << kv.first << " -> (" << kv.second.a << ", " << kv.second.b << ")\n";
}

为什么注释代码能工作

注释中的std::transform搭配std::back_inserter(v)会实际向vector插入元素,改变了vector的size,后续的std::sort和v.erase都是基于有效的元素范围执行,因此能得到正确结果。

内容的提问来源于stack exchange,提问作者Setu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:08:13