请帮我调试下面的代码。我正在做的只是将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个元素被推入矢量列表。然后我序列化向量并将其写入二进制文件并从中检索回来。它工作正常。
后来,当我在上面的代码中评论'Portion Commented'并试图直接从已经创建的二进制文件“data.data”中检索向量时,它显示了分段错误事件,尽管它在之前正确打印了4个大小for循环。这是我用这个(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
第40行是最后一个for循环中的cout
语句。有人可以帮我调试吗?还告诉我上面的代码是否可移植?
感谢, Prabu
答案 0 :(得分: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);
}
答案 1 :(得分:2)
os.write((const char*)&list[0], size1 * sizeof(string));
你在这做什么?将std::string
投射到const 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);
}
答案 2 :(得分: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
}
}
答案 3 :(得分:0)
sizeof( std::string )
为您提供string
对象的大小。实际的字符串数据本身是动态的,由string
类中的指针保存。
您可能希望使用google protocol buffer或boost serialize来序列化/反序列化对象。