Linux57:读取人脸数据库并保存到map

目录

1.本章节介绍

2.读取数据库保存到map流程框图

3.读取数据库保存到map的代码截图

[3.1. 加载并连接sqlite3数据库](#3.1. 加载并连接sqlite3数据库)

[3.2. 通过select查询人脸表格的数据](#3.2. 通过select查询人脸表格的数据)

[3.3. 读取查询的结果并循环插入map容器](#3.3. 读取查询的结果并循环插入map容器)

4.代码详解

[4.1 连接数据库](#4.1 连接数据库)

[4.2 定义 task_id](#4.2 定义 task_id)

[4.3 创建 S_THREAD_MAP 对象](#4.3 创建 S_THREAD_MAP 对象)

[thread_map 对象创建后的内存状态](#thread_map 对象创建后的内存状态)

[4.4 查询数据库](#4.4 查询数据库)

[1. sqlite3_prepare()](#1. sqlite3_prepare())

[2. sqlite3_step()](#2. sqlite3_step())

[3. sqlite3_column_text()](#3. sqlite3_column_text())

[4. sqlite3_column_int()](#4. sqlite3_column_int())

[5. sqlite3_column_blob()](#5. sqlite3_column_blob())

[6. memcpy()](#6. memcpy())

7.vector::push_back()

8.make_pair()

9.map::insert()

[4.5 赋值给 thread_map 的成员](#4.5 赋值给 thread_map 的成员)

[4.6 注册到全局](#4.6 注册到全局)

[4.7 完整执行流程图](#4.7 完整执行流程图)

扩展

1.map容器

[1.1 查找相关函数](#1.1 查找相关函数)

[1.2 插入相关函数](#1.2 插入相关函数)

[1.3 删除相关函数](#1.3 删除相关函数)

[1.4 容量相关函数](#1.4 容量相关函数)

[1.5 迭代器相关函数](#1.5 迭代器相关函数)

[1.6 修改相关函数](#1.6 修改相关函数)

[1.7 查找操作详解](#1.7 查找操作详解)

2.stmt和从数据库提取数据

[2.1、stmt 的本质](#2.1、stmt 的本质)

2.2、实际执行过程详解

[2.2.1 准备SQL语句](#2.2.1 准备SQL语句)

[2.2.2 第一次调用 sqlite3_step()](#2.2.2 第一次调用 sqlite3_step())

[2.2.3 提取数据](#2.2.3 提取数据)

1.提取姓名(第0列)

2.提取特征大小(第1列)

3.提取特征数据(第2列)

4.提取图片大小(第3列)

5.提取图片数据(第4列)

[2.2.4 继续下一行](#2.2.4 继续下一行)

2.3完整数据提取流程图

[3.string str(name)](#3.string str(name))

3.1.内存对比

3.2.原因


1.本章节介绍

本章节主要介绍如何通过查询人脸数据库数据库表格把数据存储到map容器,map容器底层是内存处理,用map去处理数据能够达到高效,快速查询的效果。在这个项目里面,map起到了快速查询的功能,key存储的是人脸的结构体(People),value存储的是人脸具体的数据(rockx_face_feature_t)。

2.读取数据库保存到map流程框图

上图是读取数据库并加载到Map的过程,分别有三步:第一步,加载并连接sqlite3数据库、第二步:通过select查询人脸表格的数据、第三步:把表格的数据循环插入到map容器。

3.读取数据库保存到map的代码截图

init_face_data 是读取数据库数据并插入到map容器的自定义函数,这里有几个重要的步骤分别是加载数据库(Connection_sqlite3DataBase)、查询数据库信息并存放到Map容器(QueryPeopleData )、把Map存放到全局变量里面(set_thread_map)

3.1. 加载并连接 sqlite3 数据库

这里封装了一个了SQLITE3连接数据库的函数Connection_sqlite3Database,这个函数的实现如下图

这个函数直接调用了sqlite3的api sqlite3_open来初始化人脸数据库,若返回值不等于SQLITE_OK则初始化数据库失败,否则就初始化成功。

3.2. 通过 select 查询人脸表格的数据

上图是通过sql语句查询人脸表格,"select name, feature_size, face_feature, image_size, image_data from face_data_table ", 其中name : 名字、feature_size : 特征值长度、face_feature: 人脸特征数据、image_size : 图片长度、image_data : 图片数据。face_data_table则是存储人脸的数据库表格。并使用sqlite3_prepare 进行sql的预处理**。**

3.3. 读取查询的结果并循环插入 map 容器

上图是读取sqlite3数据库的数据,并循环插入到map容器。这里的关键是使用了sqlite3提供的函数sqlite3_step来获取select的结果,若结果等于SQLITE_ROW( 表示当前返回结果有数据) 则表示有数据,就获取每一行的数据库数据。

sqlite3_column_text(stmt, 0) : 表示的是查找select语句的第一个元素name,索引号是0,类型是字符串,并进行绑定。

sqlite3_column_int(stmt, 1) : 表示的是查找select语句的第二个元素feature_size,索引号是1,类型是int, 并进行绑定。

sqlite3_column_blob(stmt, 2) : 表示的是查找select语句的第三个元素face_feature,索引号是2,类型是blob, 并进行绑定。

sqlite3_column_int(stmt, 3) : 表示的是查找select语句的第四个元素image_size,索引号是3,类型是int, 并进行绑定。

sqlite3_column_blob(stmt, 4) : 表示的是查找select语句的第五个元素image_data,索引号是4,类型是blob, 并进行绑定。

读取完上述的数据后,就把上述的数据插到map。

4.代码详解

4.1 连接数据库

int Connection_sqlite3DataBase()

|---------|---------------------|
| 功能 | 打开SQLite3数据库连接 |
| 参数 | 无 |
| 返回值 | 0-成功,失败则exit(1)退出程序 |

4.2 定义 task_id

int task_id = 0;

定义 task_id,标识当前任务或线程的ID编号

4.3 创建 S_THREAD_MAP 对象

S_THREAD_MAP thread_map;
class S_THREAD_MAP {

public:

int map_id;
map<string, rockx_face_feature_t> thread_map;
map<People, rockx_face_feature_t> thread_people_map;

};

|----------|----------------|
| | map_id |
| 类型 | int |
| 访问权限 | public(公开) |
| 用途 | 存储这个map对象的ID编号 |
| 当前值 | 未初始化(垃圾值) |

|----------|-------------------------------------|
| | thread_map |
| 类型 | map<string, rockx_face_feature_t> |
| 访问权限 | public |
| 用途 | 存储 姓名→人脸特征 的映射表 |
| 当前状态 | 空map |

typedef struct {

float feature512; // 512维特征向量

int len; // 特征长度,固定512

} rockx_face_feature_t;

map 容器说明:

  • 键(key):string类型,存储姓名
  • 值(value):rockx_face_feature_t类型,存储512维特征向量
  • 特点:自动按姓名排序

map容器详细使用看扩1

|----------|-------------------------------------|
| | thread_people_map |
| 类型 | map<People, rockx_face_feature_t> |
| 访问权限 | public |
| 用途 | 存储 People对象→人脸特征 的映射表 |
| 当前状态 | 空map |

struct People {

string people_name; // 姓名

vector<char> images; // 图片二进制数据

};

thread_map 对象创建后的内存状态

thread_map (对象)

│

├── map_id = ? (垃圾值,未初始化)

├── thread_map = {} (空map)

└── thread_people_map = {} (空map)

4.4 查询数据库

map<People, rockx_face_feature_t> maps = QueryPeopleData();

|---------|-----------------------------------------------------|
| 功能 | 从数据库查询所有人脸完整数据 |
| 参数 | 无 |
| 返回值 | map<People, rockx_face_feature_t> - People到特征的映射表 |

cs 复制代码
map<People, rockx_face_feature_t> QueryPeopleData()
{
  rockx_face_feature_t rockx_face_feature = {0, 0};
  map<People, rockx_face_feature_t> people_map;
  sqlite3_stmt *stmt;
  char *sql = "select name, feature_size, face_feature, image_size, image_data from face_data_table";

  int id = 0, len = 0;
  char *name;
  int feature_size;
  int image_size;
  vector<char> images;
  People first_people;

  int ret = sqlite3_prepare(db, sql, strlen(sql), &stmt, 0);
  if (ret == SQLITE_OK)
  {
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
      name = (char *)sqlite3_column_text(stmt, 0);
      printf("name = %s\n", name);
      feature_size = sqlite3_column_int(stmt, 1);
      printf("feature_size = %d\n", feature_size);

      const void *feature = sqlite3_column_blob(stmt, 2);
      memset(rockx_face_feature.feature, 0, feature_size);
      memcpy(rockx_face_feature.feature, feature, feature_size);
      rockx_face_feature.len = feature_size;

      image_size = sqlite3_column_int(stmt, 3);
      printf("image_size = %d\n", image_size);

      const char *image_data = (const char *)sqlite3_column_blob(stmt, 4);
      for (int i = 0; i < image_size; i++)
      {
        images.push_back(image_data[i]);
      }

      first_people.people_name = string(name);
      first_people.images = images;

      string str(name);
      // people_map.insert(pair<const People, rockx_face_feature_t>(first_people, rockx_face_feature));
      people_map.insert(make_pair(first_people, rockx_face_feature));
      // people_map.insert(first_people, rockx_face_feature);
    }
  }

数据提详细流程看扩2

1. sqlite3_prepare()
cs 复制代码
sqlite3_stmt *stmt;
char *sql = "select name, feature_size, face_feature, image_size, image_data from face_data_table";
int sqlite3_prepare(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail)

|----------------|------------------|
| 功能 | 将SQL语句编译成字节码 |
| 参数1 db | 数据库句柄 |
| 参数2 zSql | SQL语句字符串 |
| 参数3 nByte | SQL长度,-1表示自动计算 |
| 参数4 ppStmt | 输出参数,返回预处理语句对象 |
| 参数5 pzTail | 未使用部分指针 |
| 返回值 | SQLITE_OK(0)表示成功 |

2. sqlite3_step()

int sqlite3_step(sqlite3_stmt *pStmt)

项目 说明
功能 执行预处理语句,移动到下一行结果
参数 预处理语句句柄
返回值 SQLITE_ROW - 还有一行数据
SQLITE_DONE - 没有更多数据
3. sqlite3_column_text()

const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int iCol)

|--------------|------------------------------------|
| 功能 | 获取当前行的文本列数据 |
| 参数1 | 预处理语句句柄 |
| 参数2 iCol | 列索引,0表示第1列(name字段) |
| 返回值 | const unsigned char* - 指向文本数据的指针 |

4. sqlite3_column_int()

int sqlite3_column_int(sqlite3_stmt *pStmt, int iCol)

|--------------|-------------|
| 功能 | 获取当前行的整数列数据 |
| 参数1 | 预处理语句句柄 |
| 参数2 iCol | 列索引 |
| 返回值 | 整数值 |

5. sqlite3_column_blob()

const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int iCol)

|--------------|----------------------------|
| 功能 | 获取当前行的二进制数据 |
| 参数1 | 预处理语句句柄 |
| 参数2 iCol | 列索引 |
| 返回值 | const void* - 指向二进制数据的指针 |

6. memcpy()

void *memcpy(void *dest, const void *src, size_t n)

|--------------|--------|
| 功能 | 拷贝内存区域 |
| 参数1 dest | 目标地址 |
| 参数2 src | 源地址 |
| 参数3 n | 拷贝的字节数 |
| 返回值 | 目标地址 |

7.vector::push_back()
cs 复制代码
const char *image_data = (const char *)sqlite3_column_blob(stmt, 4);
for (int i = 0; i < image_size; i++)
{
    images.push_back(image_data[i]);
}

从数据库读取二进制的图片数据,逐字节复制到 vector<char> 容器中。

void push_back(const T& value)

项目 说明
功能 在vector末尾添加一个元素
参数 要添加的元素值
返回值 无
vector的长度自动增加1

图示

执行前

执行中(逐字节复制)

执行后

8.make_pair()

pair<People, rockx_face_feature_t> make_pair(People first, rockx_face_feature_t second)

项目 说明
功能 创建一对键值对
参数1 键(People对象)
参数2 值(特征向量)
返回值 pair对象
9.map::insert()

pair<iterator, bool> insert(const value_type& val)

项目 说明
功能 向map中插入键值对
参数 pair对象
返回值 pair<迭代器, 是否成功>

QueryPeopleData() 开始

│

▼

┌─────────────────────────────┐

│ sqlite3_prepare() │

│ 编译SQL语句 │

└─────────────────────────────┘

│

▼

┌─────────────────────────────┐

│ while(sqlite3_step()) │

│ 遍历每一行数据 │

└─────────────────────────────┘

│

▼

┌─────────────────────────────┐

│ sqlite3_column_text(stmt,0) │

│ 提取数据库信息 │

└─────────────────────────────┘

│

▼

┌─────────────────────────────┐

│ sqlite3_column_blob(stmt,4) │

│ 提取图片数据 │

│ for循环 push_back() │

│ 拷贝到 vector<char> │

└─────────────────────────────┘

│

▼

┌─────────────────────────────┐

│ 构建 People 对象 │

│ people_name = name │

│ images = 图片数据 │

└─────────────────────────────┘

│

▼

┌─────────────────────────────┐

│ make_pair() + insert() │

│ 存入 people_map │

└─────────────────────────────┘

│

▼

┌─────────────────────────────┐

│ 返回 people_map │

└─────────────────────────────┘

返回值 maps 的内容

maps (map<People, rockx_face_feature_t>)

│

├── 键: People1 (姓名="张三", 图片数据)

│ 值: rockx_face_feature (512维特征)

│

├── 键: People2 (姓名="李四", 图片数据)

│ 值: rockx_face_feature (512维特征)

│

└── 键: People3 (姓名="王五", 图片数据)

值: rockx_face_feature (512维特征)

4.5 赋值给 thread_map 的成员

thread_map.thread_people_map = maps;

项目 说明
左操作数 thread_map.thread_people_map - S_THREAD_MAP对象的成员
右操作数 maps - QueryPeopleData()返回的map
操作 将maps赋值给thread_people_map

赋值后的状态

thread_map (对象)

│

├── map_id = ? (仍是垃圾值)

├── thread_map = {} (仍然是空map)

└── thread_people_map = maps (包含数据库所有人脸数据)

4.6 注册到全局

S_THREAD_MAP g_thread_mapsMAX_MAP_NUM; //类对象数组,全局存储

set_thread_map(task_id, &thread_map);

int set_thread_map(unsigned int map_id, S_THREAD_MAP *map)

{

pthread_mutex_lock(&g_thread_maps_mutex);

g_thread_mapsmap_id = *map;

pthread_mutex_unlock(&g_thread_maps_mutex);

return 0;

}

项目 说明
功能 将线程数据注册到全局管理器中
参数1 task_id 任务ID,这里是0
参数2 thread_map 指向S_THREAD_MAP对象的指针

4.7 完整执行流程图

扩展

1.map容器

1.1 查找相关函数

函数 功能 参数 返回值
find(key) 根据键查找元素位置 key:要查找的键 找到返回指向该元素的迭代器,没找到返回 end()
count(key) 统计键出现的次数 key:要统计的键 map中返回0或1(因为键不能重复)
lower_bound(key) 查找第一个不小于key的位置 key:比较的键 返回指向第一个 >= key 的迭代器
upper_bound(key) 查找第一个大于key的位置 key:比较的键 返回指向第一个 > key 的迭代器
equal_range(key) 获取等于key的范围 key:要查找的键 返回一个pair,包含lower_bound和upper_bound

1.2 插入相关函数

函数 功能 参数 返回值
insert(pair) 插入一个键值对 pair<Key,Value> 对象 返回pair<迭代器,bool>,bool表示是否插入成功
insert(init_list) 插入多个元素 初始化列表 无
emplace(args) 原地构造并插入 构造键值对的参数 返回pair<迭代器,bool>
emplace_hint(pos, args) 带提示位置的插入 pos:插入位置提示,args:构造参数 返回迭代器

m"key" = 100; // 方式1:下标(最常用)

m.insert({"key", 100}); // 方式2:初始化列表

m.insert(make_pair("key", 100)); // 方式3:make_pair

m.insert(pair<string,int>("key",100)); // 方式4:pair

1.3 删除相关函数

函数 功能 参数 返回值
erase(key) 按键删除元素 key:要删除的键 返回删除的元素个数(0或1)
erase(iterator) 按迭代器位置删除 iterator:指向要删除元素的迭代器 返回被删除元素的下一个迭代器
erase(first, last) 删除范围内的元素 first:起始位置,last:结束位置 无
clear() 清空所有元素 无 无

1.4 容量相关函数

函数 功能 参数 返回值
size() 获取元素个数 无 map中键值对的数量
empty() 判断是否为空 无 true表示空,false表示非空
max_size() 获取最大容量 无 map能容纳的最大元素个数

1.5 迭代器相关函数

函数 功能 参数 返回值
begin() 获取第一个元素的迭代器 无 指向第一个元素的迭代器
end() 获取尾后迭代器 无 指向最后一个元素之后位置的迭代器
rbegin() 获取反向第一个元素的迭代器 无 指向最后一个元素的反向迭代器
rend() 获取反向尾后迭代器 无 指向第一个元素之前的反向迭代器
cbegin() 获取常量正向迭代器 无 不能修改元素的begin()
cend() 获取常量尾后迭代器 无 不能修改元素的end()

1.6 修改相关函数

函数 功能 参数 返回值
at(key) 访问指定键的值(带边界检查) key:要访问的键 返回值的引用,不存在抛异常
operator\[\] 下标访问运算符 key:要访问的键 返回值的引用,不存在则自动创建
swap(map) 交换两个map的内容 map:要交换的另一个map对象 无

1.7 查找操作详解

find(key) 是最常用的

项目 说明
功能 在map中查找指定的键
参数 key - 要查找的键值
返回值 找到 → 返回指向该元素的迭代器(可以访问键和值)
没找到 → 返回 end()(尾后迭代器)
时间复杂度 O(log n)

count(key) 用于快速判断存在

项目 说明
功能 统计指定键出现的次数
参数 key - 要统计的键
返回值 0 - 键不存在
1 - 键存在
时间复杂度 O(log n)

at(key) 安全的访问方式

项目 说明
功能 访问指定键对应的值
参数 key - 要访问的键
返回值 键存在 → 返回值的引用
键不存在 → 抛出 out_of_range 异常
时间复杂度 O(log n)

operator\[\] 最方便但有风险

项目 说明
功能 访问或创建指定键对应的值
参数 key - 要访问/创建的键
返回值 键存在 → 返回已有值的引用
键不存在 → 自动创建并返回默认值的引用
时间复杂度 O(log n)
注意 即使只读取,如果键不存在也会自动创建!

2.stmt和从数据库提取数据

2.1、stmt 的本质

sqlite3_stmt *stmt;

项目 说明
stmt 是什么 预处理语句对象(Prepared Statement)
它保存什么 SQL语句的编译结果 (字节码)
它不保存什么 不保存查询结果数据
工作原理 像是一个"迭代器",逐行移动获取数据

2.2、实际执行过程详解

2.2.1 准备SQL语句

sqlite3_prepare(db, sql, strlen(sql), &stmt, 0); // 编译SQL语句

SELECT name, feature_size, face_feature, image_size, image_data

FROM face_data_table

假设数据库中有3条记录:

行号 name feature_size face_feature image_size image_data
1 张三 512 0.1,0.2,... 102400 0xFF,0xD8,...
2 李四 512 0.3,0.4,... 98000 0xFF,0xD8,...
3 王五 512 0.5,0.6,... 105000 0xFF,0xD8,...

此时 stmt 的状态:

2.2.2 第一次调用 sqlite3_step()

while (sqlite3_step(stmt) == SQLITE_ROW)

sqlite3_step() 函数详解

项目 说明
功能 执行预处理语句,并移动到下一行结果
参数 stmt - 预处理语句句柄
返回值 SQLITE_ROW - 成功移动到一行数据
SQLITE_DONE - 没有更多数据
SQLITE_ERROR - 执行出错

执行过程:

第1次调用 sqlite3_step(stmt)

↓

返回 SQLITE_ROW,指向第1行数据

↓

执行循环体内的代码(处理第1行)

↓

第2次调用 sqlite3_step(stmt)

↓

返回 SQLITE_ROW,指向第2行数据

↓

执行循环体内的代码(处理第2行)

↓

第3次调用 sqlite3_step(stmt)

↓

返回 SQLITE_ROW,指向第3行数据

↓

执行循环体内的代码(处理第3行)

↓

第4次调用 sqlite3_step(stmt)

↓

返回 SQLITE_DONE(没有第4行了)

↓

退出 while 循环

此时:

stmt 的游标向下移动一行

↓

┌─────────────────────────────────────────┐

│ 第1行: 张三,512,特征,102400,图片 ← 现在指向这行 │

│ 第2行: 李四,512,特征,98000,图片 │

│ 第3行: 王五,512,特征,105000,图片 │

└─────────────────────────────────────────┘

stmt 内部保存了当前行的"位置"

但数据还在数据库里,没有复制到 stmt 中!

2.2.3 提取数据

1.提取姓名(第0列)

name = (char *)sqlite3_column_text(stmt, 0);

printf("name = %s\n", name);

|---------|------------------------------------|
| 功能 | 获取当前行指定列的文本类型数据 |
| 参数1 | stmt - 预处理语句句柄 |
| 参数2 | 0 - 列索引,0表示第1列(name字段) |
| 返回值 | const unsigned char* - 指向文本数据的指针 |

name 的类型是 char*,需要强制类型转换

此时:

  1. SQLite 根据 stmt 保存的位置,去数据库找到第1行

  2. 取出第1行的第0列数据

  3. 把数据复制到内存中

  4. 返回指向这个内存的指针

stmt 本身仍然不保存数据,只是知道去哪里取!
当前指向第1行:name列的值是 "张三"

sqlite3_column_text(stmt, 0) 返回 → 指向 "张三" 的指针

↓

name = 那个指针

↓

printf("%s", name) 输出 → 张三

2.提取特征大小(第1列)

feature_size = sqlite3_column_int(stmt, 1);

printf("feature_size = %d\n", feature_size);
当前指向第1行:feature_size列的值是 512

sqlite3_column_int(stmt, 1) 返回 → 512

↓

feature_size = 512

↓

printf 输出 → feature_size = 512

3.提取特征数据(第2列)

const void *feature = sqlite3_column_blob(stmt, 2); //获取数据指针

memset(rockx_face_feature.feature, 0, feature_size); //清空目标缓冲区

memcpy(rockx_face_feature.feature, feature, feature_size); //拷贝数据

rockx_face_feature.len = feature_size; //设置长度

sqlite3_column_blob() 函数详解

项目 说明
功能 获取当前行指定列的二进制数据
参数1 stmt - 预处理语句句柄
参数2 2 - 列索引,2表示第3列(face_feature字段)
返回值 const void* - 指向二进制数据的指针

人脸特征是一个 512维的float数组,占用 512 × 4 = 2048 字节,是二进制数据,不能用文本存储。

这里有问题

memset(rockx_face_feature.feature, 0, feature_size);

memcpy(rockx_face_feature.feature, feature, feature_size);

feature_size 的值是 512 (特征维度数),但实际字节数应该是 512 × sizeof(float) = 2048!

正确写法:

int feature_bytes = feature_size * sizeof(float); // 512 * 4 = 2048

memset(rockx_face_feature.feature, 0, feature_bytes);

memcpy(rockx_face_feature.feature, feature, feature_bytes);

4.提取图片大小(第3列)

image_size = sqlite3_column_int(stmt, 3);

printf("image_size = %d\n", image_size);

|----------|-----------------------|
| 列索引 | 3 - 第4列(image_size字段) |
| 数据类型 | INTEGER |
| 存储内容 | 图片文件的字节数(如 102400) |

5.提取图片数据(第4列)

const char *image_data = (const char *)sqlite3_column_blob(stmt, 4);

数据库中的 image_data 字段存储的是原始图片文件的完整内容:

2.2.4 继续下一行

sqlite3_step(stmt); // 移动到第2行

此时:

stmt 的游标移动到第2行

┌─────────────────────────────────────────┐

│ 第1行: 张三,512,特征,102400,图片 │

│ 第2行: 李四,512,特征,98000,图片 ← 现在指向这行 │

│ 第3行: 王五,512,特征,105000,图片 │

└─────────────────────────────────────────┘

之前第1行的数据?已经被释放或覆盖了!

2.3完整数据提取流程图

3.string str(name)

项目 说明
string C++标准库中的字符串类
str 定义了一个string类型的变量,变量名是str
name 一个char*类型的C风格字符串指针
整体作用 将C风格字符串(char*)转换为C++ string对象

3.1.内存对比

转换前 (name):

name (char*指针)

│

▼

┌────┬────┬────┬────┬────┬────┬────┐

│ '张' │ '三' │ '\0' │ │ │ │ │

└────┴────┴────┴────┴────┴────┴────┘

C风格:以\0结尾的字符数组

3.转换后 (str):

str (string对象)

┌─────────────────────────────┐

│ 内部包含: │

│ - 指向堆内存的指针 │

│ - 字符串长度 (2) │

│ - 容量大小 │

└─────────────────────────────┘

│

▼

┌────┬────┐

│ '张' │ '三' │

└────┴────┘

C++风格:知道长度,不依赖\0

3.2.原因

场景1:存入map(最常见原因)

cs 复制代码
map<string, rockx_face_feature_t> rockx_face_feature_map;

// ❌ 不能直接用 char* 作为map的键
// map 要求键是 string 类型

// ✅ 需要转换为 string
string str(name);
rockx_face_feature_map[str] = rockx_face_feature;
// 或者
rockx_face_feature_map.insert(pair<string, rockx_face_feature_t>(str, rockx_face_feature));

场景2:赋值给其他string变量

cs 复制代码
People first_people;
first_people.people_name = string(name);  // 直接转换并赋值
// 等价于:
string str(name);
first_people.people_name = str;
相关推荐
神一样的老师2 分钟前
WS63 访问 HTTPS 握手失败(-0x7780)根治
数据库·网络协议·https
Patrick在香港22 分钟前
时间戳凭空早了 8 小时:datetime.utcnow() 弃用实测与漂移复盘
数据库·python·标准库·datetime·时区·弃用
李兆龙的博客8 小时前
问津集 #26:Lakebase——Postgres 的版本化页面存储、数据库分支与计算弹性
数据库
倔强的石头_10 小时前
聊聊金仓KFS:一款把数据同步软件做扎实的产品
数据库
闲云野鹤在人间11 小时前
MySQL|从理论、安装、备份到主从复制、MHA高可用详解
linux·运维·数据库·mysql·云计算
禾小西11 小时前
Redis:从两大维度和三大主线建立知识体系
数据库·redis·缓存
禾小西11 小时前
Redis 数据结构:快速的 Redis 有哪些慢操作?
数据结构·数据库·redis
数据库小学妹12 小时前
数据共享交换平台选型:交换方式对比与避坑指南
数据库·信创·数据同步·数据交换平台·政务数据共享·数据共享交换平台·数据库底座
loong_XL13 小时前
决策模型做内容安全检测:从踩坑到上线
数据库·安全·jev·决策模型
这个DBA有点耶13 小时前
数据库双轨并行实战:全量并行策略、增量延迟控制、双向回切与一致性校验
数据库·架构·dba