unique_ptr 丢失范围时读取访问冲突
unique_ptr read access violation when losing scope
我正在使用 std::ifstream 从二进制文件中读取一个 char 数组,然后将 char 数组重新解释为指向我的结构的指针,然后将其设为 unique_ptr。
一切正常,除非 unique_ptr 超出范围,我会遇到读取访问冲突。
我是不是做错了?我不确定为什么会发生错误。关于那个数据我只有一个 unique_ptr。
我已经包含了产生错误的代码的最基本版本。
struct mystruct {
int val = 0;
double val2 = 5.6;
std::string string = "test";
};
int main()
{
//brackets here just to encapsulate the scope for this example
{
//try to open the stream for reading
std::ifstream stream;
stream.open("test.bin", std::ios::binary | std::ios::in);
char* buffer = new char[sizeof(mystruct)];
stream.read(buffer, sizeof(mystruct));
mystruct * pointer = reinterpret_cast<mystruct*>(buffer);
std::unique_ptr<mystruct> obj = std::unique_ptr<mystruct>(pointer);
//ha no problem reading the struct data
std::cout << "read back: " << obj->string << endl;
stream.close();
}
//obj goes out of scope and throws a read access violation
}
我希望 unique_ptr 只删除对象并且不会抛出任何错误
************编辑*********************
感谢您的评论和回答 - 基本上是在您的帮助下,我生成了我试图这样做的代码,因此已在此处列出,以防它对其他人有所帮助。
要点是:
* 如果从二进制读取和写入,不建议在结构中使用 std::string,因为 std::string 的字节数未知。
* 需要在将指针分配给它之前在内存中创建对象 - std::make_unique() 适合于此。
struct mystruct {
int val1 = 0;
double val2 = 5.6;
char somestring[10] = "string";
};
int main()
{
//brackets here just to encapsulate the scope for this example
{
//try to open the stream for reading
std::ifstream stream;
stream.open("test.bin", std::ios::binary | std::ios::in);
//hold the results in a vector
auto results = std::vector<std::unique_ptr<mystruct>>();
//read a vectory or mystructs from the binary file
while (!stream.eof())
{
//create the object - NOTE: make_unique initialises my struct
std::unique_ptr<mystruct> obj = std::make_unique<mystruct>();
//read from binary file into obj
if (!stream.read(reinterpret_cast<char*>(obj.get()), sizeof mystruct))
break;
//add the obj to th vector
results.push_back(std::move(obj));
}
stream.close();
for (auto& val : results)
{
cout << "read back: " << val->somestring << endl;
}
}
}
您的代码中存在 3 种未定义的行为。
首先,你假装在一个实际上没有物体的地方有一个物体。您从未创建过 mystruct
;你刚刚分配了一些内存字节。仅仅做一个 reinterpret_cast
不足以创造一个 mystruct
。因此,任何访问不存在的 "object" 的 pointer
的使用都是 UB。
其次,即使那个缓冲区中有一个,mystruct
也不是可以简单复制的,所以你不能只是复制它的字节。您不能将一堆字节读入 non-trivially 可复制对象。 non-trivially 可复制 non-static 数据成员(即:mystruct::string
)的存在使其 non-trivially 可复制。
第三,您尝试删除此 mystruct
。但是没有mystruct
,你是在删除一个不存在的东西。从技术上讲,#1 可能涵盖了这一点,但这可能是导致您的代码彻底崩溃的原因。
如果您知道 "no problem reading the struct data" 碰巧起作用的原因,那么 std::string
实现使用小字符串优化的可能性很大,如果它存储在 std::string
本身中的字符串足够小。对于小字符串,按字节复制可能足以接近 "working" 以允许您读取字符串数据。
但这只是运气而已。
我正在使用 std::ifstream 从二进制文件中读取一个 char 数组,然后将 char 数组重新解释为指向我的结构的指针,然后将其设为 unique_ptr。 一切正常,除非 unique_ptr 超出范围,我会遇到读取访问冲突。
我是不是做错了?我不确定为什么会发生错误。关于那个数据我只有一个 unique_ptr。
我已经包含了产生错误的代码的最基本版本。
struct mystruct {
int val = 0;
double val2 = 5.6;
std::string string = "test";
};
int main()
{
//brackets here just to encapsulate the scope for this example
{
//try to open the stream for reading
std::ifstream stream;
stream.open("test.bin", std::ios::binary | std::ios::in);
char* buffer = new char[sizeof(mystruct)];
stream.read(buffer, sizeof(mystruct));
mystruct * pointer = reinterpret_cast<mystruct*>(buffer);
std::unique_ptr<mystruct> obj = std::unique_ptr<mystruct>(pointer);
//ha no problem reading the struct data
std::cout << "read back: " << obj->string << endl;
stream.close();
}
//obj goes out of scope and throws a read access violation
}
我希望 unique_ptr 只删除对象并且不会抛出任何错误
************编辑*********************
感谢您的评论和回答 - 基本上是在您的帮助下,我生成了我试图这样做的代码,因此已在此处列出,以防它对其他人有所帮助。
要点是:
* 如果从二进制读取和写入,不建议在结构中使用 std::string,因为 std::string 的字节数未知。
* 需要在将指针分配给它之前在内存中创建对象 - std::make_unique() 适合于此。
struct mystruct {
int val1 = 0;
double val2 = 5.6;
char somestring[10] = "string";
};
int main()
{
//brackets here just to encapsulate the scope for this example
{
//try to open the stream for reading
std::ifstream stream;
stream.open("test.bin", std::ios::binary | std::ios::in);
//hold the results in a vector
auto results = std::vector<std::unique_ptr<mystruct>>();
//read a vectory or mystructs from the binary file
while (!stream.eof())
{
//create the object - NOTE: make_unique initialises my struct
std::unique_ptr<mystruct> obj = std::make_unique<mystruct>();
//read from binary file into obj
if (!stream.read(reinterpret_cast<char*>(obj.get()), sizeof mystruct))
break;
//add the obj to th vector
results.push_back(std::move(obj));
}
stream.close();
for (auto& val : results)
{
cout << "read back: " << val->somestring << endl;
}
}
}
您的代码中存在 3 种未定义的行为。
首先,你假装在一个实际上没有物体的地方有一个物体。您从未创建过 mystruct
;你刚刚分配了一些内存字节。仅仅做一个 reinterpret_cast
不足以创造一个 mystruct
。因此,任何访问不存在的 "object" 的 pointer
的使用都是 UB。
其次,即使那个缓冲区中有一个,mystruct
也不是可以简单复制的,所以你不能只是复制它的字节。您不能将一堆字节读入 non-trivially 可复制对象。 non-trivially 可复制 non-static 数据成员(即:mystruct::string
)的存在使其 non-trivially 可复制。
第三,您尝试删除此 mystruct
。但是没有mystruct
,你是在删除一个不存在的东西。从技术上讲,#1 可能涵盖了这一点,但这可能是导致您的代码彻底崩溃的原因。
如果您知道 "no problem reading the struct data" 碰巧起作用的原因,那么 std::string
实现使用小字符串优化的可能性很大,如果它存储在 std::string
本身中的字符串足够小。对于小字符串,按字节复制可能足以接近 "working" 以允许您读取字符串数据。
但这只是运气而已。