简体   繁体   English

向量序列化/反序列化中的C ++分段错误

[英]C++ Segmentation Fault in vector serialize/deserialize

Please help me debug the below code. 请帮我调试下面的代码。 What I am doing is just serialize vector<string> into binary file and retrieving it back from it. 我正在做的只是将vector<string>序列化为二进制文件并从中检索它。 Here is the example main code, 这是示例主代码,

    /*  Portion Commented */
vector<string> list;

list.push_back("AAAAAA");
list.push_back("BBBBBB");
list.push_back("CCCCCC");
list.push_back("DDDDDD");

// Write out a list to a disk file
ofstream os ("/home/test/data.dat", ios::binary);

int size1 = list.size();
os.write((const char*)&size1, sizeof(int));
os.write((const char*)&list[0], size1 * sizeof(string));
os.close();
/* Portion Commented */

// Read it back in
VertexList list2;

ifstream is("/home/test/data.dat", ios::binary);
int size2;
is.read((char*)&size2, sizeof(int));

list2.resize(size2);
cout<<"Size is :"<<size2<<endl;
is.read((char*)&list2[0], size2 * sizeof(string));
for (int i=0; i < size2; i++)
{
        cout<<"At i = "<<i<<", "<<list2[i]<<endl;   //Line 40 in my program
}

I have 4 elements pushed into vector list. 我有4个元素被推入矢量列表。 Then I serialize the vector and write it in a binary file and retrieving it back from same. 然后我序列化向量并将其写入二进制文件并从中检索回来。 It works fine. 它工作正常。

Later when I comment the 'Portion Commented' in the above code and tried to retrieve the vector directly from the already created binary file "data.data", it shows segmentation fault event though it prints the size correctly as 4 just before the for loop. 后来当我在上面的代码中评论'Portion Commented'并试图直接从已经创建的二进制文件“data.data”中检索向量时,它显示了分段错误事件,尽管它在for循环之前正确地打印了4的大小。 This is my valgrind output created with this ( valgrind --leak-check=yes ./a.out ), 这是我用这个创建的valgrind输出( valgrind --leak-check=yes ./a.out ),

==14058== Invalid read of size 8  
==14058==    at 0x4EBE263: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib/libstdc++.so.6.0.14)  
==14058==    by 0x40107F: main (test2.cpp:40)  
==14058==  Address 0x2156010 is not stack'd, malloc'd or (recently) free'd 

Line 40 is the cout statement in the last for loop. 第40行是最后一个for循环中的cout语句。 Can someone help me debug this ? 有人可以帮我调试吗? Also tell me whether the above code is portable or not ? 还告诉我上面的代码是否可移植?

thanks, Prabu 谢谢,Prabu

The implementation of std::string includes a pointer to the actual string contents on the heap. std::string的实现包括指向堆上实际字符串内容的指针。 So, sizeof(string) is just the pointer plus some bytes. 因此, sizeof(string)只是指针加上一些字节。 If you want to write the string, you must write the contents itself 如果要编写字符串,则必须自己编写内容

for (auto i = list.begin(); i != list.end(); ++i) {
    os.write(i->c_str(), i->size() + 1);
}

When you read that back in, you must look for the terminating NUL byte. 当您重读时,必须查找终止NUL字节。 Alternatively, you can save the length of the string, as you have done with the list 或者,您可以像保存列表一样保存字符串的长度

for (auto i = list.begin(); i != list.end(); ++i) {
    int len = i->size() + 1;
    os.write((const char*)&len, sizeof(len));
    os.write(i->c_str(), i->size() + 1);
}
os.write((const char*)&list[0], size1 * sizeof(string));

What are you doing here? 你在这里做什么? Casting std::string into const char* ? std::string转换为const char* That doesn't make sense. 这没有意义。

If you use C++-style cast, the compiler will tell you why it doesn't make sense. 如果您使用C ++样式转换,编译器将告诉您为什么它没有意义。 That is why C++ programmers should avoid using C-style cast! 这就是为什么C ++程序员应该避免使用C风格的演员!

What you probably want to do is this: 你可能想做的是:

os.write(list[0].c_str(), list[0].size() + 1);

And you should do that in a loop as: 你应该在一个循环中这样做:

for(auto const & s : list) //s is inferred to be std::string
{
  os.write(s.c_str(), s.size() + 1);
}

In C/C++, you should not save the structure or class for serialization, unless you know the implementation and there are no pointers in that. 在C / C ++中,您不应该保存序列化的结构或类,除非您知道实现并且没有指针。
The better way is to use boost serialization. 更好的方法是使用boost序列化。 They already did everything to support serialize/deserialize STL objects. 他们已经做了一切来支持序列化/反序列化STL对象。

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
int main(int ac, char **av)
{
    vector<string> list1;

    list1.push_back("AAAAAA");
    list1.push_back("BBBBBB");
    list1.push_back("CCCCCC");
    list1.push_back("DDDDDD");

    // Write out a list to a disk file
    ofstream os ("data.dat", ios::binary);

    boost::archive::binary_oarchive oa(os);
    oa << list1;
    os.close();

    vector<string> list2;

    ifstream is("data.dat", ios::binary);
    boost::archive::binary_iarchive ia(is);
    ia >> list2;
    int size2 = list2.size();
    for (int i=0; i < size2; i++)
    {
       cout<<"At i = "<<i<<", "<<list2[i]<<endl;   //Line 40 in my program
    }
}

sizeof( std::string ) gives you size of the string object. sizeof( std::string )给出了string对象的大小。 Actual string data itself is dynamic and held by a pointer in string class. 实际的字符串数据本身是动态的,并由string类中的指针保存。

You might want to use google protocol buffer or boost serialize for serialize/de-serialize objects. 您可能希望使用google协议缓冲区boost序列化来序列化/反序列化对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM