3

请帮我调试下面的代码。我正在做的只是序列vector<string>化成二进制文件并从中检索它。这是示例主要代码,

    /*  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
}

我有 4 个元素被推入向量列表。然后我序列化向量并将其写入二进制文件并从中检索它。它工作正常。

后来,当我在上面的代码中注释“部分注释”并尝试直接从已经创建的二进制文件“data.data”中检索向量时,它显示了分段错误事件,尽管它在 for 循环之前将大小正确打印为 4 . valgrind --leak-check=yes ./a.out这是我用这个 ( )创建的 valgrind 输出,

==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 

第 40 行是cout最后一个 for 循环中的语句。有人可以帮我调试吗?还告诉我上面的代码是否可移植?

谢谢, 普拉布

4

4 回答 4

3

的实现std::string包括指向堆上实际字符串内容的指针。所以,sizeof(string)只是指针加上一些字节。如果要写字符串,必须自己写内容

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

当你读回它时,你必须寻找终止的 NUL 字节。或者,您可以保存字符串的长度,就像您对列表所做的那样

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);
}
于 2012-11-15T11:49:08.450 回答
2
os.write((const char*)&list[0], size1 * sizeof(string));

你在这里做什么?铸造std::stringconst char*? 那没有意义。

如果你使用 C++ 风格的强制转换,编译器会告诉你为什么它没有意义。这就是为什么 C++ 程序员应该避免使用 C 风格的强制转换!

您可能想要做的是:

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

你应该在一个循环中这样做:

for(auto const & s : list) //s is inferred to be std::string
{
  os.write(s.c_str(), s.size() + 1);
}
于 2012-11-15T11:49:00.633 回答
1

在 C/C++ 中,您不应该保存结构或类以进行序列化,除非您知道实现并且其中没有指针。
更好的方法是使用 boost 序列化。他们已经尽一切努力支持序列化/反序列化 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
    }
}
于 2012-11-15T13:03:36.007 回答
0

sizeof( std::string )给你string对象的大小。实际的字符串数据本身是动态的,并由string类中的指针保存。

您可能想要使用google 协议缓冲区提升序列化来序列化/反序列化对象。

于 2012-11-15T11:52:15.347 回答