结构体中std::string转char*出现首字符未定义问题排查
问题:std::string转char*存储到结构体后首段字符出现未定义值
我希望将std::string转换为带有size_t长度信息的char并存储到结构体中,之后再还原为std::string。但后续获取该char或还原字符串时,首段字符始终呈现未定义值,以下是最小示例代码及运行输出:
#include <iostream> #include <string> struct Data { Data(std::string string) : m_data(string.data()), m_size(string.size()) { std::cout << "String size: " << m_size << std::endl; std::cout << "String in constructor: "; for (int j = 0; j < m_size; ++j) { std::cout << (m_data)[j]; } std::cout << std::endl; } char* m_data; size_t m_size; static void print_string(Data model_data) { std::cout << "String in static function: "; for (int j = 0; j < model_data.m_size; ++j) { std::cout << model_data.m_data[j]; } std::cout << std::endl; } }; int main() { std::string test_string = "Hello World! The next characters might appear..."; Data test_data(test_string); Data::print_string(test_data); std::cout << "String from member: "; for (int j = 0; j < test_data.m_size; ++j) { std::cout << test_data.m_data[j]; } return 0; }
运行输出:
String size: 48 String in constructor: Hello World! The next characters might appear... String in static function: �~v��� next characters might appear... String from member: �~v��� next characters might appear...%
问题原因
核心问题是你存储的是临时std::string对象的内部指针,具体细节:
- 构造函数
Data(std::string string)的参数是按值传递,传入的test_string会被复制出一个临时std::string对象。 string.data()返回的指针指向这个临时对象内部的字符数组。- 构造函数执行完成后,临时std::string对象会被销毁,其内部的字符数组也会被释放,此时
m_data就变成了悬空指针。 - 后续访问悬空指针指向的内存属于未定义行为,首段字符乱码就是这种行为的表现,后续内容看似正常只是内存还没被覆盖的巧合。
正确实现方案
方案1:直接存储std::string(推荐)
让结构体持有std::string,无需手动管理内存,简单安全:
#include <iostream> #include <string> struct Data { std::string m_data; Data(std::string string) : m_data(std::move(string)) { std::cout << "String size: " << m_data.size() << std::endl; std::cout << "String in constructor: " << m_data << std::endl; } static void print_string(Data model_data) { std::cout << "String in static function: " << model_data.m_data << std::endl; } }; int main() { std::string test_string = "Hello World! The next characters might appear..."; Data test_data(test_string); Data::print_string(test_data); std::cout << "String from member: " << test_data.m_data << std::endl; return 0; }
方案2:手动分配内存存储char*(需注意内存管理)
如果必须使用char*,需要手动分配内存并复制字符串内容,同时要处理内存释放:
#include <iostream> #include <string> #include <algorithm> struct Data { char* m_data; size_t m_size; Data(const std::string& string) : m_size(string.size()) { // 分配内存,+1可选,用于兼容C风格字符串的结束符 m_data = new char[m_size + 1]; std::copy(string.begin(), string.end(), m_data); m_data[m_size] = '\0'; // 可选,添加结束符 std::cout << "String size: " << m_size << std::endl; std::cout << "String in constructor: " << m_data << std::endl; } // 析构函数释放内存 ~Data() { delete[] m_data; } // 禁用拷贝构造和赋值,避免浅拷贝导致重复释放内存 Data(const Data&) = delete; Data& operator=(const Data&) = delete; // 可选:实现移动构造和移动赋值 Data(Data&& other) noexcept : m_data(other.m_data), m_size(other.m_size) { other.m_data = nullptr; other.m_size = 0; } Data& operator=(Data&& other) noexcept { if (this != &other) { delete[] m_data; m_data = other.m_data; m_size = other.m_size; other.m_data = nullptr; other.m_size = 0; } return *this; } static void print_string(Data model_data) { std::cout << "String in static function: "; for (size_t j = 0; j < model_data.m_size; ++j) { std::cout << model_data.m_data[j]; } std::cout << std::endl; } }; int main() { std::string test_string = "Hello World! The next characters might appear..."; Data test_data(test_string); Data::print_string(std::move(test_data)); // 使用移动避免拷贝(因为拷贝被禁用) // 注意:test_data此时已处于移动后的状态,不能再使用 return 0; }
内容的提问来源于stack exchange,提问作者faressc
相关产品推荐
相关产品推荐

