I have started to learn C++ some weeks ago and now I have a problem with my current project.
I wanted to write templates, that allow me to save objects into binary datas and load them again later. Here ist the code of these templates:
#ifndef TOOLS_H
#define TOOLS_H
#include <fstream>
#include <string>
namespace Tools
{
template <class T>
void writeBinaryFile(std::string filename, T object)
{
std::ofstream of(filename, std::ios::out | std::ios::binary);
of.write((char*) &object, sizeof(T));
of.close();
}
template <class P>
P readBinaryFile(std::string filename)
{
P temp;
std::ifstream ifs(filename, std::ios::in | std::ios::binary);
ifs.read((char*) &temp, sizeof(P));
ifs.close();
return temp;
}
}
#endif
I created a class called GameSettings. The header data is:
#ifndef GAMESETTINGS_H
#define GAMESETTINGS_H
#include <iostream>
#include <string>
#include "SFML\Graphics.hpp"
class GameSettings
{
public:
GameSettings();
GameSettings(std::string playerName, bool sound, int volume, int level);
~GameSettings();
void setPlayerName(std::string playername){ playerName = playername; };
void setSound(bool sound){ this->sound = sound; };
void setVolume(int volume){ this->volume = volume; };
void setLevel(int level){ this->level = level; };
const std::string getPlayerName() { return playerName; }
const bool getSound() { return sound; }
const int getVolume() { return volume; }
const int getLevel() { return level; }
private:
std::string playerName;
bool sound;
int volume;
int level;
};
#endif
With the cpp-data:
#include "GameSettings.h"
GameSettings::GameSettings(std::string playerName, bool sound, int volume, int level)
{
this->playerName = playerName;
this->sound = sound;
this->volume = volume;
this->level = level;
}
GameSettings::GameSettings():
playerName(""),
sound(true),
volume(0),
level(0)
{
}
GameSettings::~GameSettings()
{
}
When I start the main-function:
#include <iostream>
#include "GameSettings.h"
#include "Tools.h"
int main()
{
GameSettings* gs = new GameSettings("Andrew", true, 100, 3);
Tools::writeBinaryFile<GameSettings>("gamesettings.bin", *gs);
gs->setPlayerName("TEST");
*gs = Tools::readBinaryFile<GameSettings>("gamesettings.bin");
std::cout << gs->getPlayerName();
std::getchar();
return 0;
}
an error occurs:
Unhandled exception at 0x5a1cad54 (msvcp100d.dll) in Mohrhuhn.exe: 0xC0000005: Access violation writing location 0xfeeefeee.
Can somebody help me?
Sincerly, Andrew
I think the root of the trouble is
*gs = Tools::readBinaryFile<GameSettings>("gamesettings.bin");
You read raw bytes to a variable that contains std::string. It may ruin char pointer inside it. So, any call to playerName should fail or result in UB.
Only POD types can be read/write this way. A bit more I found on another web-page: http://www.cplusplus.com/forum/general/39764/
The template you implement to serialize the object will not work because casting the std::string to char* and saving sizeof(std::string) will not save the content of the string.
Check the saved file, but I guess you need to implement properly serialization and deserialization.
First of all writing down binary files by just dumping them from memory is a bad idea since you might incur in lots of additional problems (e.g. shallow copies, polimorphism, etc..)
return temp;
You are returning a temporary object that is being destroyed after the function exits.
Change your code into
gs = Tools::readBinaryFile<GameSettings>("gamesettings.bin");
...
template <class P>
P* readBinaryFile(std::string filename)
{
P* temp = new P();
std::ifstream ifs(filename, std::ios::in | std::ios::binary);
ifs.read((char*) temp, sizeof(P));
ifs.close();
return temp;
}
and everything will work out properly (psst. remember to free the memory!)
Related
#include <iostream>
class Model
{
public:
Model(const char *a)
{
message=a;
}
const char *car() { return message; }
const char *message;
};
class ModelCar
{
public:
ModelCar(const char *sn, const char *b="c")
{
filename=strdup(sn);
f=fopen(sn,b);
if (f==NULL)
{
throw Model("File can't be opened");
}
}
~ModelCar()
{
delete [] filename;
if (fclose(f)<0)
{
throw Model("File can't be closed");
}
}
void read(char *buf, int size)
{
if (fread(buf, 1, size, f)!=size)
{
throw Model("File can't be read");
}
}
const char *filename;
FILE *f;
};
Why I am getting error: ‘strdup’ was not declared in this scope , I tried and add #include <string.h> but still getting error
Can anyone please help me what is wrong in this code
First of all I suggest you to fix some problems with the code:
1.
delete [] filename;
filename=strdup(sn);
Okay your delete function suggests that your filename is a dynamic array which you never intialized. Also have you looked at what strdup returns, it returns a dynamic char, not an dynamic array. I would suggest you change:
delete [] filename;
to
free(filename);
So I'm trying to use the Cereal library and I've come to an issue I can't seem to overcome. Essentially the doc's say it is possible to deserialize Types with no default constructor. Yet in the implementation notes it says Define a serialize or save/load pair as you normally would yet the serialize/load options cannot be defined in a valid manner if there is no default constructor. I take this to mean, the load_and_construct function takes the place of load. Yet when implementing a relatively simple example seen below.
"main.cpp"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <memory>
#include <cereal/access.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/portable_binary.hpp>
struct string_wrapper {
const std::string str;
string_wrapper(const std::string& _a) : str{_a} {}
template <class Archive>
void save(Archive& _archive) const {
_archive(str);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<string_wrapper>& _construct) {
std::string a;
_archive(a);
_construct(a);
}
};
struct wrapper_of_string_wrappers {
const std::vector<string_wrapper> strs;
wrapper_of_string_wrappers(
const std::vector<string_wrapper>& _a
) : strs{_a} { }
template <class Archive>
void save(Archive& _archive) const {
_archive(strs);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<wrapper_of_string_wrappers>& _construct) {
std::vector<string_wrapper> strs;
_archive(strs);
_construct(strs);
}
};
int main() {
auto file = "test.bin";
{ // save
std::ofstream os(file, std::ios::binary);
cereal::PortableBinaryOutputArchive archiveSave(os);
std::vector<string_wrapper> as;
as.push_back({"Hello"});
as.push_back({"World"});
wrapper_of_string_wrappers test(as);
auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
archiveSave(test_ptr);
}
{ // load
std::ifstream is(file, std::ios::binary);
cereal::PortableBinaryInputArchive archiveLoad(is);
std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
archiveLoad(test);
std::cout << (*test).strs[0].str << " " << (*test).strs[1].str << std::endl;
}
std::cin.get();
return 0;
}
This code obviously is kind of pointless, its just a minimal example to illustrate the problem I'm running into.
From this page
Non-default constructors are currently only supported for serializing pointers
Your problem here is you are trying to serialize non pointer values with no default constructor here
std::vector<string_wrapper> strs;
_archive(strs);
To solve your problem you need either make default constructor for string_wrapper with save/load pair or use string_wrapper as pointer in wrapper_of_string_wrappers.
Here is working code for second option(string_wrapper remains same):
struct wrapper_of_string_wrappers {
//const std::vector<std::unique_ptr<string_wrapper>> strs;
//const string_wrapper strs;
const std::unique_ptr<string_wrapper> strs;
wrapper_of_string_wrappers(
//const std::vector<std::unique_ptr<string_wrapper>>& _a
const string_wrapper _a
) : strs{ new string_wrapper(_a) } { }
wrapper_of_string_wrappers(
const wrapper_of_string_wrappers& w
) : strs{ new string_wrapper(*w.strs) } { }
template <class Archive>
void save(Archive& _archive) const {
_archive(strs);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<wrapper_of_string_wrappers>& _construct) {
//std::vector<std::unique_ptr<string_wrapper>> strs;
std::unique_ptr<string_wrapper> strs;
_archive(strs);
_construct(*strs);
}
};
int main() {
auto file = "test.bin";
{ // save
std::ofstream os(file, std::ios::binary);
cereal::PortableBinaryOutputArchive archiveSave(os);
string_wrapper as("Hello");
wrapper_of_string_wrappers test(as);
auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
archiveSave(test_ptr);
}
{ // load
std::ifstream is(file, std::ios::binary);
cereal::PortableBinaryInputArchive archiveLoad(is);
std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
archiveLoad(test);
std::cout << (*test).strs->str << std::endl;
}
std::cin.get();
return 0;
}
I created child class of ofstream. I want to pass in constructor mode of file. For example ios::app. How can i do it ? What should i write in my_file constructor to put it in ofstream class constructor? I know that it's int type but how to understand what is value of ios::app?
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
class my_file : public ofstream {
string name;
public:
my_file(string name, const char* filename) : ofstream(filename) { this->name = name; }
inline const string get() { return this->name; }
};
int main(void) {
my_file file("Name","new.txt" /* , ios::app */ );
return 0;
}
I know that it's int type but how to understand what is value of ios::app?
Wrong, that's not a int!
Go to ofstream doc http://www.cplusplus.com/reference/fstream/ofstream/, then click (constructor) to see what the parameters are and then you can see that mode is of type std::ios_base::openmode (as described here)
So simply do:
class my_file : public ofstream {
string name;
public:
my_file(string name, const char* filename, std::ios_base::openmode mode ) : ofstream(filename,mode) { this->name = name; }
inline const string get() { return this->name; }
};
Then:
my_file file("Name","new.txt", ios::app);
i was writing a class like this
class AA{
private:
char* str;
public:
AA(int size){
str = (char*)malloc(size);
}
};
int main(){
AA anAA(1000);
}
here is the problem, when the size is too big it may cause malloc return a 0 pointer, if the str init fail, is there any method to return a 0 pointer to anAA(in the main entry point, i can check anAA isn't init success by if(anAA != NULL)), i don't want to make a function for creating AA class, or make a check function in the class
I'll ignore the atrocities you are committing in favour of answering your question.
The easiest solution, if you don't want to use exceptions, is to define an operator bool():
class AA{
...
public:
operator bool() const {
return this->str != nullptr; // return str; would actually suffice
}
};
int main(){
AA anAA(1000);
if (!anAA) {
std::cerr << "Creating object failed.\n";
return 1;
}
return 0;
}
#include <iostream>
#include <stdexcept> // std::exception
#include <stdlib.h> // EXIT_FAILURE
#include <string> // std::string
#include <vector> // std::vector
using namespace std;
class AA{
private:
string str_;
public:
AA( int const size)
{
str_.reserve( size );
}
};
int main()
{
try
{
AA anAA( 1000 );
// Whatever
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
return EXIT_FAILURE;
}
}
Note 1: with this approach you probably don't need to reserve a size upfront.
Note 2: I chose reserve as probably the closest thing to a presumed intention of making sure that str_ can hold at least that long a string without failure, a preallocation of resources.
Disclaimer: I've not compiled this code.
I am trying to get this to return a string, but i am having trouble getting it working. The goal is to have a doubly-linked list that points to strings. I am not allowed to have it contain the string, it must point to it instead. Currently i am having trouble getting my program to use it. For example, it always seems to return what the command was, and its confusing me and hard to explain.
#ifndef DOUBLY_LINKED_LIST_H
#define DOUBLY_LINKED_LIST_H
#include <iostream>
#include <string>
//#include "Playlist.h"
using namespace std;
class DoublyLinkedList
{
public:
DoublyLinkedList();
~DoublyLinkedList();
bool empty();
void append(string& s);
void insertBefore(string& s);
void insertAfter(string& s);
void remove(string& s);
void begin();
void end();
bool next();
bool prev();
bool find(string& s);
const string& getData();
private:
class Node
{
public:
Node (string *data, Node *next, Node *prev)
{m_data = data; m_next = next; m_prev = prev;}
string *m_data;
Node * m_next;
Node * m_prev;
};
Node *m_head;
Node *m_tail;
Node *m_current;
};
#endif // DOUBLYLINKEDLIST_H_INCLUDED
.cpp file>>>>
const string& DoublyLinkedList::getData()
{
string *m_tmp;
m_tmp = m_current->m_data;
cout << m_current->m_data << endl;
//cout << "returning: " << m_current->m_data << endl;
// return m_current->m_data;
return *m_tmp;
}
void DoublyLinkedList::append(string &s)
{
if (!m_head)
{
m_head = new Node(&s, NULL, NULL);
m_tail = m_head;
m_current = m_head;
}
else
{
m_tail->m_next = new Node (&s, NULL, m_tail);
m_tail = m_tail->m_next;
m_current = m_tail;
}
}
Consider the following example:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void store_value(vector<string*>& vec, string& str)
{
vec.push_back(&str);
}
void create_and_store_value(vector<string*>& vec)
{
string str("This string is temporary");
store_value(vec, str);
}
int main(int argc, char** argv)
{
vector<string*> pointers;
create_and_store_value(pointers);
cout << *pointers.back() << endl;
string myPersistingString("Yay");
store_value(pointers, myPersistingString);
cout << *pointers.back() << endl;
return 0;
}
This example contains two function, a function store_value which behaves similar to your append function (except, for the purposes of this example working on a std::vector) and a second function showing the possible danger of taking the address of a reference (this is one of the possible hazards that I believe Manu343726 and Mats Petersson are preluding too).
The reason this is dangerous is because the string declared inside create_and_store_value does not persist after the completion of the function. This means that we are left with a pointer to memory which is probably not what we expect. On the other hand, creating a string inside the main function is fine, since the string there persists until the end of the program.
For us to help you further, I would suggest editing your question to give us an example of how you are calling your function. I would suggest pasting a minimal striped down version of your code including an example of how you are calling append, something like:
#include <blah>
class DoubleLinkedList
{
DoubleLinkedList(void)
{
// Include these inline to make copying and pasting simpler.
}
~DoubleLinkedList(void)
{
...
}
append(...) { ... }
getData(...) { ... }
};
int main(int argc, char** argv)
{
DoubleLinkedList dll;
// Show us how you are using this list
return 0;
}
In the above, replace the comments and dots with the relevant code.