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

使用看似相同字符串键访问std::map时at()抛出std::out_of_range异常

std::map使用const char*作为键的访问异常问题解析

问题现象

使用const char*作为std::map的键时,字符串字面量可以正常调用at()访问,但std::string::c_str()的返回值调用时会抛出std::out_of_range异常。已验证两者字符串内容、长度、strcmp结果完全一致,但问题仍存在。

示例代码

#include <map>
#include <string>
#include <string.h>
#include <stdio.h>


typedef enum
{
    CODING_RATE_4_5,  // Modem default
    CODING_RATE_4_6
} lora_modem_cfg_coding_rate_t;

static std::map<const char*, lora_modem_cfg_coding_rate_t> CreateCodingRateMap()
{
    std::map<const char*, lora_modem_cfg_coding_rate_t> newMap;
    newMap["CODING_RATE_4_5"] = CODING_RATE_4_5;
    newMap["CODING_RATE_4_6"] = CODING_RATE_4_6;
    return newMap;
}


int main(void)
{
    std::map<const char*, lora_modem_cfg_coding_rate_t> codingRateMap = CreateCodingRateMap();

    const char* coding_rate_selection1 = "CODING_RATE_4_5";

    std::string coding_rate_selection2_string = "CODING_RATE_4_5";
    const char* coding_rate_selection2 = coding_rate_selection2_string.c_str();

    printf("coding_rate_selection1: %s\n", coding_rate_selection1);
    printf("coding_rate_selection2: %s\n", coding_rate_selection2);
    printf("coding_rate_selection1 strlen: %ld\n", strlen(coding_rate_selection1));
    printf("coding_rate_selection2 strlen: %ld\n", strlen(coding_rate_selection2));
    printf("strcmp: %d\n", strcmp(coding_rate_selection1, coding_rate_selection2));

    for (uint8_t idx = 0; idx < 20; idx++)
        printf("%2d %02X %02X\n", idx, coding_rate_selection1[idx], coding_rate_selection2[idx]);
    printf("\n");

    lora_modem_cfg_coding_rate_t codingRate;
    codingRate = codingRateMap.at(coding_rate_selection1);
    printf("%s %d\n", __FILE__, __LINE__);  fflush(stdout);

    codingRate = codingRateMap.at(coding_rate_selection2);
    printf("%s %d\n", __FILE__, __LINE__);  fflush(stdout);

    return 0;
}

运行输出

coding_rate_selection1: CODING_RATE_4_5
coding_rate_selection2: CODING_RATE_4_5
coding_rate_selection1 strlen: 15
coding_rate_selection2 strlen: 15
strcmp: 0
 0 43 43
 1 4F 4F
 2 44 44
 3 49 49
 4 4E 4E
 5 47 47
 6 5F 5F
 7 52 52
 8 41 41
 9 54 54
10 45 45
11 5F 5F
12 34 34
13 5F 5F
14 35 35
15 00 00
16 43 0A
17 4F D7
18 44 39
19 49 C4

map_test.cpp 47
terminate called after throwing an instance of 'std::out_of_range'
  what():  map::at
Aborted (core dumped)

原因解析

std::map默认使用std::less<Key>作为比较器,当Key是const char*时,比较的是指针的内存地址,而非字符串内容:

  1. 字符串字面量(如"CODING_RATE_4_5")会被编译器存入程序的常量字符串池,相同内容的字面量会复用同一个内存地址,因此coding_rate_selection1的地址和CreateCodingRateMap中插入的字面量地址一致,at()能找到对应条目。
  2. std::string::c_str()返回的是指向std::string内部堆内存缓冲区的指针,这个地址和常量池中的字面量地址完全不同,map会判定这是一个不存在的键,进而抛出std::out_of_range异常。

解决方案

方案1:将map的键类型改为std::string(推荐)

std::string的std::less比较器会按字符串内容进行比较,完全符合预期,且无需额外处理:

// 修改map的键类型
static std::map<std::string, lora_modem_cfg_coding_rate_t> CreateCodingRateMap()
{
    std::map<std::string, lora_modem_cfg_coding_rate_t> newMap;
    newMap["CODING_RATE_4_5"] = CODING_RATE_4_5;
    newMap["CODING_RATE_4_6"] = CODING_RATE_4_6;
    return newMap;
}

int main(void)
{
    std::map<std::string, lora_modem_cfg_coding_rate_t> codingRateMap = CreateCodingRateMap();
    // 其余代码无需修改,std::string会自动兼容const char*类型的键
}

方案2:为map自定义字符串内容比较器

如果必须使用const char*作为键,可以自定义比较器让map按字符串内容比较:

struct CStrCompare {
    bool operator()(const char* a, const char* b) const {
        return strcmp(a, b) < 0;
    }
};

// 使用自定义比较器声明map
static std::map<const char*, lora_modem_cfg_coding_rate_t, CStrCompare> CreateCodingRateMap()
{
    std::map<const char*, lora_modem_cfg_coding_rate_t, CStrCompare> newMap;
    newMap["CODING_RATE_4_5"] = CODING_RATE_4_5;
    newMap["CODING_RATE_4_6"] = CODING_RATE_4_6;
    return newMap;
}

int main(void)
{
    std::map<const char*, lora_modem_cfg_coding_rate_t, CStrCompare> codingRateMap = CreateCodingRateMap();
    // 其余代码不变
}

注意:使用const char*作为键时,必须确保所有插入的键指针指向的内存不会被释放或修改,否则会导致map行为异常。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 02:02:23