C++: Use Boost Serialization to write/read files [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I need to write/read a file that contains a std::map. The file must be read at the program start up (if it exists). Im using boost's fstream, but im getting this:
"terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): input stream error"
Well, i really dont know what is happening.. these are my lines:
map<int64_t, int64_t> foo;
filesystem::path myFile = GetWorkingDirectory() / "myfile.dat";
[...............] // some code
filesystem::ifstream ifs(myFile);
archive::text_archive ta(ifs);
if (filesystem::exists(myFile)
{
ta >> foo; // foo is empty until now, it's fed by myFile
ifs.close();
}
What im doing wrong? Any idea?
Thanks.
P.S. Note that some lines after, i need to do the reverse action: write into myfile.dat the std::map foo.
EDIT: all works if i use std::ifstream, saving the file in the same dir where im running the Application. But using boost and his path, something goes wrong.

I'm a bit miffed. You're clearly using Boost Serialization (the archive/ headers are part of this library) but somehow you're not saying anything about that. Because it's so easy to demonstrate:
Live On Coliru
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/map.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace boost;
int main() {
std::map<int64_t, int64_t> foo;
filesystem::path myFile = filesystem::current_path() / "myfile.dat";
if (filesystem::exists(myFile))
{
filesystem::ifstream ifs(myFile/*.native()*/);
archive::text_iarchive ta(ifs);
ta >> foo; // foo is empty until now, it's fed by myFile
std::cout << "Read " << foo.size() << " entries from " << myFile << "\n";
} else {
for (int i=0; i<100; ++i) foo.emplace(rand(), rand());
filesystem::ofstream ofs(myFile/*.native()*/);
archive::text_oarchive ta(ofs);
ta << foo; // foo is empty until now, it's fed by myFile
std::cout << "Wrote " << foo.size() << " random entries to " << myFile << "\n";
}
}
Prints
Wrote 100 random entries to "/tmp/myfile.dat"
And on second run:
Read 100 entries from "/tmp/myfile.dat"

Related

Why is ParseFromString() not producing an output in my application using protobuf?

I currently have a *.cpp file where I import the needed *.proto.h file and instantiate an object based on one of the messages(Heartbeat) from my *.proto file. My goal is to use the set_value(), SerializeToString(), and ParseFromString().I've had success accomplishing the first two tasks. When using ParseFromString() not output is produced to the screen. I'm pretty new to protobufs so there may be something I'm overlooking. This is my code.
#include <iostream>
#include <fstream>
#include <string>
#include "cpnt.pb.h"
using namespace std;
int main()
{
wombat::HeartBeat h;
string m;
string t;
string v;
h.set_value(1);
v = h.SerializeToString(&m);
t = h.ParseFromString(v);
cout << "\n The message received is:" << h.value();
cout << "\n The binary data stored in v is:" << v;
cout << "\n The parsed data stored in t is:" << t <<::endl;
return 0;
}
And this is a printout of the output:
You misunderstood how SerializeToString works. h.SerializeToString(&m); serializes h and stores the result in m. h.ParseFromString(v); parsed from the string v to set members of h. Hence it should be
h.set_value(1);
h.SerializeToString(&m);
h.ParseFromString(m);
Both functions retun a bool, but I admit that I didn't find what it is good for in the documentation. Probably to signal an error.

Why does the function find of C++ stl string sometimes go wrong sometime go right?

I am trying to do some file reading with C++ in Ubuntu 16.04 (GCC&G++ 5.4 and CMake 3.5.1).
The test file (named 123.txt) have only a line words just like this:
Reprojection error: avg = 0.110258 max = 0.491361
I just want to get the avg error and max error. My method is to get a line and put them into a std::string
and use string::find. My codes are very easy just like this:
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
FILE *fp = fopen("123.txt", "r");
char tmp[60];
string str;
fgets(tmp, size_t(tmp), fp);
fclose(fp);
cout << tmp << endl;
str = tmp;
cout << str.size() << endl;
size_t avg = str.find("avg");
size_t max = str.find("max");
cout << avg << endl;
cout << max << endl;
}
I can use g++ to compile it successfully. But I meet a strange issue.
When I first run it in the command, it will get the right result:
Reprojection error: avg = 0.110258 max = 0.491361
52
20
37
If I run codes again, it will go wrong sometimes just like this:
p
2
18446744073709551615
18446744073709551615
The "p" is a disorderly code which can not be shown correctly in the command. I am not good at C++ and feel confused about it. Is there someone who can say something? Thank you!
The expression
fgets(tmp, size_t(tmp), fp);
is ill-formed, size_t(tmp) will not work as you expect, you need sizeof(tmp).
The 52 value you get is because fgets consumes the \n character and this is counted too, actually the string has 51 characters counting with spaces.
That said, in this case you can use better C++ tools to replace the C ones you are using, fopen can be replaced by using the fstream library, fgets can be replaced by getline.
Something like:
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream fp("123.txt"); //C++ filestream
if (fp.is_open()) {//check for file opening errors
std::string str;
std::getline(fp, str); //C++ read from file
fp.close();
std::cout << str << std::endl;
std::cout << str.size() << std::endl;
size_t avg = str.find("avg");
size_t max = str.find("max");
std::cout << avg << std::endl;
std::cout << max << std::endl;
}
else{
std::cerr << "Couldn't open file";
}
}
Note that I dind't use using namespace std;, this is for a reason, it's not a good practice, you can check this thread for more details.

C++: Passing vector to function and then calling function in main. Missing something

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
#include <vector>
using namespace std;
void getAnswer(std::vector<std::string> &answers, int nAnswers)
{
int index = rand() % nAnswers;
}
int main()
{
std::vector<string> answers;
answers.push_back("Most Certainly");
answers.push_back("Absolutely");
answers.push_back("Yes");
answers.push_back("You Can Bet On It");
answers.push_back("Odds look good");
answers.push_back("Let's talk about that some other time");
answers.push_back("Odds don't look so good");
answers.push_back("I think you know the answer to that question");
answers.push_back("I don't think I'm qualified to answer that question");
answers.push_back("Absolutely Not");
answers.push_back("I Don't Think So");
answers.push_back("Um...no");
std::vector<string> qAnswers(answers);
answers.size();
string questionAsked;
bool pgExit = false;
srand((unsigned int)time(NULL));
cout << "\nWelcome to the Magic 8Ball.\n";
cout << "\nAsk a question and I will predict the answer!\n" << endl;
//loop and ask the user to enter a question or enter "x" to stop
while (!pgExit) {
cout << "What is your question? (Type question or Enter 'x' to exit) " << endl;
//use getline to get the question
getline(cin, questionAsked);
//call getAnswer with your array and number of possible answers to get an answer
getAnswer(answers, answers.size());
//output the answer
if (questionAsked.compare("x") == 0)
{
cout << "Maybe next time. Have a good day.";
pgExit = true;
}
if (questionAsked.compare("") != 0 && questionAsked.compare("x") != 0)
{
getAnswer;
std::cout << getAnswer(answers, answers.size()) << std::endl;
}
}
}
The issue I am having is when I compile, it is saying 'no operator matches "<<" these operands. Standard operands are: std::ostream << void'
I am not sure I understand. I am passing the vector string and the vector size to void getAnswers to get the randomize for the answers. What am I missing?
Any help is greatly appreciated.
void getAnswer(std::vector<std::string> &answers, int nAnswers)
The void return "type" states explicitly that this function returns nothing so you cannot then go and attempt to use that return value in an expression:
std::cout << getAnswer(answers, answers.size()) << std::endl;
Assuming that you will eventually return a random answer from your list of answers (based on code to date), the first thing you should do is dummy up a reurn value:
std::string getAnswer(std::vector<std::string> &answers, int nAnswers)
{
// Just return last one for now (make sure you
// have at least one in the collection).
return answers[nAnswers - 1];
}
Then you can later adapt it to provide a random one. I could have just provided the complete function but, since this is probably educational work, you'll learn a lot more by doing this yourself (this answer is just to get you over your specific problem).
I have included some sample code at the bottom for you to look over (and for future readers who may not be doing the classwork) but I urge you to try yourself first.
As an aside, you should also be aware that you have some rather superfluous lines in your code, specifically:
answers.size();
getAnswer(answers, answers.size());
getAnswer;
None of these do anything useful, they simply evaluate the expression and throw away the result.
I'm also not why you attempt to create a second vector from the original, especially since you don't use it anywhere:
std::vector<string> qAnswers(answers);
As mentioned earlier, my sample code follows. Please do not use it verbatim if you value your marks (or integrity) - any educator worth their salt will be using plagiarism detection tools:
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
#include <vector>
// Anon namespace to hide this in translation unit.
namespace {
// No need to pass in size, vector has this.
const std::string &getAnswer(const std::vector<std::string>answers) {
return answers[std::rand() % answers.size()];
}
};
int main() {
srand(static_cast<unsigned int>(time(nullptr)));
// Can be const if initialised rather than each entry pushed.
const std::vector<std::string> answers = {
"Most Certainly", "Absolutely", "Yes", "You Can Bet On It",
"Odds look good", "Let's talk about that some other time",
"Odds don't look so good",
"I think you know the answer to that question",
"I don't think I'm qualified to answer that question",
"Absolutely Not", "I Don't Think So", "Um...no",
};
std::cout << "\nWelcome to the Magic 8Ball.\n";
std::cout << "\nAsk a question and I will predict the answer!\n";
// Infinite loop, use break to exit.
while (true) {
// Ask and get response.
std::cout << "\nWhat is your question (x to exit)? " << std::endl;
std::string questionAsked;
std::getline(std::cin, questionAsked);
// Exit loop if told so.
if (questionAsked == "x") {
std::cout << "Maybe next time. Have a good day.\n\n";
break;
}
// Answer any non-blank question.
if (! questionAsked.empty()) {
std::cout << getAnswer(answers) << '\n';
}
}
}

Serialization using boost library [duplicate]

This question already has an answer here:
Outputting more things than a Polymorphic Text Archive
(1 answer)
Closed 6 years ago.
I'm trying to use boost library to serialize std::map so that is possible to store it in a file. However I'm having so weird behaviours (i guess). So here is my code:
#include <map>
#include <fstream>
#include <iostream>
#include <bitset>
#include <boost/serialization/map.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
std::map<int,int> map = {{65,2}, {69,1}, {75,1} ,{77,1}, {82,1}, {84,2}, {89,2}};
void saveMapToFile(std::ofstream& f);
int main()
{
std::ofstream f("test.txt", std::ios::binary);
saveMapToFile(f);
std::cout << "position: " << f.tellp() << std::endl;
}
void saveMapToFile(std::ofstream& f)
{
std::cout << "position : " << f.tellp() << std::endl;
boost::archive::text_oarchive oarch(f);
std::cout << "position : " << f.tellp() << std::endl;
oarch << map;
std::cout << "position : " << f.tellp() << std::endl;
}
And here is the above code's output:
position : 0
position : 28
position : 75
position: 76
So can someone explain to me what is happening here? Why position after insterting map (in function) in different outside of it? I don't do any additional opperations, yet that pointer goes one byte further... Am I missing something? Thanks for your help in advance.
I don't see why you would be making assumptions about the implementation of the archive format.
Archives write headers, and can write "trailers" (think XML archives).
The destructor of oarch wrote another byte, finishing the stream. It could be a sentinel, a checksum, a newline etc.

"Roll-Back" or Undo Any Manipulators Applied To A Stream Without Knowing What The Manipulators Were [duplicate]

This question already has answers here:
Restore the state of std::cout after manipulating it
(9 answers)
Closed 4 years ago.
If I apply an arbitrary number of manipulators to a stream, is there a way to undo the application of those manipulators in a generic way?
For example, consider the following:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << "Hello" << hex << 42 << "\n";
// now i want to "roll-back" cout to whatever state it was in
// before the code above, *without* having to know
// what modifiers I added to it
// ... MAGIC HAPPENS! ...
cout << "This should not be in hex: " << 42 << "\n";
}
Suppose I want to add code at MAGIC HAPPENS that will revert the state of the stream manipulators to whatever it was before I did cout << hex. But I don't know what manipulators I added. How can I accomplish this?
In other words, I'd like to be able to write something like this (psudocode/fantasy code):
std::something old_state = cout.current_manip_state();
cout << hex;
cout.restore_manip_state(old_state);
Is this possible?
EDIT:
In case you're curious, I'm interested in doing this in a custom operator<<() I'm writing for a complex type. The type is a kind of discriminated union, and different value types will have different manips applied to the stream.
EDIT2:
Restriction: I cannot use Boost or any other 3rd party libraries. Solution must be in standard C++.
Yes.
You can save the state and restore it:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
std::ios state(NULL);
state.copyfmt(std::cout);
cout << "Hello" << hex << 42 << "\n";
// now i want to "roll-back" cout to whatever state it was in
// before the code above, *without* having to know what modifiers I added to it
// ... MAGIC HAPPENS! ...
std::cout.copyfmt(state);
cout << "This should not be in hex: " << 42 << "\n";
}
If you want to get back to the default state you don't even need to save the state you can extract it from a temporary object.
std::cout.copyfmt(std::ios(NULL));
The standard manipulators all manipulate a stream's format flags, precision and width settings. The width setting is reset by most formatted output operations anyway. These can all be retrieved like this:
std::ios_base::fmtflags saveflags = std::cout.flags();
std::streamsize prec = std::cout.precision();
std::streamsize width = std::cout.width();
and restored:
std::cout.flags( saveflags );
std::cout.precision( prec );
std::cout.width( width );
Turning this into an RAII class is an exercise for the reader...
Saving and restoring state is not exception-safe. I would propose to shuffle everything into a stringstream, and finally you put that on the real stream (which has never changed its flags at all).
#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
std::ostringstream out;
out << "Hello" << std::hex << 42 << "\n";
std::cout << out.str();
// no magic necessary!
std::cout << "This should not be in hex: " << 42 << "\n";
}
Of course this is a little less performant. The perfect solutions depends on your specific needs.
Boost IO State saver might be of help.
http://www.boost.org/doc/libs/1_40_0/libs/io/doc/ios_state.html
I know that is an old question, but for future generations:
You can also write a simple state saver yourself (it will certainly help you avoid leaving the state changed). Just use the solution suggested by #loki and run it from the constructor/destructor of an object (in short: RAII) along these lines:
class stateSaver
{
public:
stateSaver(ostream& os): stream_(os), state_(nullptr) { state_.copyfmt(os); }
~stateSaver() { stream_.copyfmt(state_); }
private:
std::ios state_;
ostream& stream_;
};
Then, you will use it like this:
void myFunc() {
stateSaver state(cout);
cout << hex << 42 << endl; // will be in hex
}
int main() {
cout << 42 << endl; // will be in dec
myFunc();
cout << 42 << endl; // will also be in dec
}