std::vector.data()是最直接安全的获取内部连续存储首地址的方式,非空时返回t*,空时返回nullptr;需确保vector生命周期长于指针使用期,避免悬垂指针。

std::vector.data() 是最直接的获取方式
只要 std::vector 非空,data() 就返回指向其内部连续存储首地址的 T*,等价于原生数组指针。它不拷贝数据,零开销,是标准且安全的做法。
常见错误是误用 &vec[0] —— 当 vec.empty() 时会解引用空容器,触发未定义行为;而 data() 在空 vector 下明确返回 nullptr,可安全判空。
- 必须确保 vector 生命周期长于指针使用期,否则悬垂指针
- 不能对
data()返回的指针调用delete[],内存由 vector 管理 - 若后续调用
push_back、resize等可能使 vector 重新分配,原指针立即失效
需要真正复制成独立原生数组时用 new + memcpy 或循环赋值
当必须脱离 vector 独立存在(比如传给 C 接口且对方要长期持有或释放内存),就得手动分配新内存并复制内容。
别用 std::copy(vec.begin(), vec.end(), new T[vec.size()]) 这种写法——它没保存数组长度,且容易忘 delete[];更稳妥的是封装为 RAII 类型,或至少用 std::unique_ptr<t></t> 管理。
-
new T[vec.size()]分配后,用std::copy(vec.begin(), vec.end(), raw_ptr)复制 - 若类型
T无默认构造(如含引用成员),不能用new T[n],改用malloc+placement new(极少见) - 注意
std::vector<bool></bool>是特化,data()不可用,必须逐位复制
传给 C 函数时,优先传 data() + size(),而非强行转数组
绝大多数 C 接口(如 glBufferData、fwrite、sqlite3_bind_blob)都接受“指针 + 长度”组合,根本不需要“变成数组”。硬转反而增加风险和冗余代码。
例如:some_c_func(vec.data(), vec.size() * sizeof(T)) 就足够了。传 &vec[0] 要加 !vec.empty() 判定,不如 data() 干净。
- 确认 C 函数是否修改数据:若会写入,需保证 vector 容量足够(
reserve不够,得resize) - 若 C 函数要求以
\0结尾的字符串,std::vector<char></char>可用data(),但必须确保末尾有\0(vec.push_back(0)或额外分配) - 跨 DLL 边界传递 raw 指针时,注意 STL 实现差异(如 MSVC 的 debug/release 运行时不兼容),此时应避免暴露 vector 内部布局
std::span 是现代 C++ 更安全的替代方案
C++20 引入 std::span,本质是“带长度的非拥有视图”,能无缝绑定 vector、原生数组、data()+size 组合,且编译期检查边界(debug 模式下)。
它不解决“转成原生数组”的需求,但消除了大多数非要转的动机——因为 std::span 本身就能被设计为接受视图的函数直接消费。
- 声明:
std::span<const int> s(vec);</const>或std::span<int> s(vec.data(), vec.size());</int> - 传参比裸指针更自文档化,且支持范围 for、
subspan等操作 - 若目标平台不支持 C++20,可用 span-lite 作为头文件级替代
真正需要“转成原生数组”的场景其实很少,多数时候是误解了接口契约或过度担心性能。重点盯住生命周期、所有权和重分配时机,比纠结语法转换更重要。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











