Class A contains a template function which reads an object into a string by first passing it to a stringstream and then converting the stream to a string.
For the life of me, I don't know why these objects aren't passed to the stream. What could be the problem? What could I try to resolve this?
class A
{
public:
template<class T>
void Input(const T&);
private:
std::string result;
};
template<class T>
void A::Input(const T& obj)
{
//Pass object to the stream
std::ostringstream ss;
ss << obj;
//After this line, result == "" with size 1 (??), no matter the input
result = ss.str();
int test = 1234;
ss << test;
//Even with a test int, result == "" with size 1 (???)
result = ss.str();
}
EDIT: I'm using Visual Studio Pro 2012.
Related
I have currently a function
int myfun(const int a) {
...
return rval;
}
that performs several actions.
I mean to adapt it to write debug information on its behaviour or not according to some parameter that I can pass.
In the cases I want to write that info, I also want to pass the ofstream to use.
And I want applications that were using myfun to still work with no modifications.
So I would ideally change to
int myfun(const int a, ofstream & ofs) {
...
if (!(ofs == NULL)) {
ofs << ...
}
...
if (!(ofs == NULL)) {
ofs << ...
}
return rval;
}
with a default value similar to &ofs=NULL. I know NULL is not appropriate.
What is an appropriate way of handling this?
Note 1:
I could pass an optional parameter with the output file name, but that is less flexible.
Note 2:
I could also change to
int myfun(const int a, const bool debug_info, ofstream & ofs) {
...
if (debug_info) {
ofs << ...
}
with a default value debug_info=false.
I guess this still requires a default value for ofs as above.
Note 3:
The accepted answer in Default ofstream class argument in function proposes an overload without the ofs parameter.
In my case that may not work, as I mean to not write anything when "ofs=NULL".
Note 4:
This other answer apparently works, but it seems somewhat contrived to me, and I am not sure it provides all the same functionality as with passing an ofs.
Related:
Is there a null std::ostream implementation in C++ or libraries?
I want applications that were using myfun to still work with no modifications.
If so, use an ofs with default nullptr
int myfun(const int a, ofstream *ofs = nullptr)
{
if (ofs != nullptr)
{
// (*ofs) << ... ;
}
// ...
}
You can't use a reference parameter ofstream& ofs for such function because a reference cannot be null.
Make an abstract Logger class. It has a method for logging a message. In derived classes you can add logging to file (ofstream) or simply do nothing. You can use any logger, the implementation of myfun() stays the same.
#include <fstream>
class Logger {
public:
virtual void log(const char*) = 0;
};
class NullLogger: public Logger {
public:
void log(const char*) override {};
};
class FileLogger: public Logger {
public:
FileLogger(std::ofstream& s): ofs(s){}
void log(const char* msg) override {
ofs << msg;
}
private:
std::ofstream& ofs;
};
static NullLogger defaultLogger;
int myfun(const int a, Logger& logger=defaultLogger)
{
logger.log("hello");
// ...
logger.log("asdf");
}
int main(){
std::ofstream ofs;
FileLogger fileLogger(ofs);
NullLogger nullLogger;
myfun(10,fileLogger); // logs to file
myfun(10,nullLogger); // logs nothing
myfun(10); // also logs nothing
return 0;
}
In C++17 there is a solution involving std::optional but since it requires default constructible types, std::reference_wrapper has to be used too.
#include <fstream>
#include <optional>
#include <functional>
int myfun(const int a, std::optional<std::reference_wrapper<std::ofstream>> ofs)
{
if (ofs) {
ofs->get() << "...";
return 1;
}
else{
return 0;
}
}
#include <iostream>
int main(){
std::ofstream file;
//Calling is quite nice.
std::cout<<myfun(10,{file})<<'\n'; //Prints 1
std::cout<<myfun(10,{})<<'\n'; //Prints 0
}
The downside of this solution, although idiomatic, is being verbose and heavy on the syntax in some cases.
I want to write a class that can monitor a bunch of different values for easy debugging. Imagine setting "watches" in a visual debugger. I'm picturing something like this:
struct Foo {
int x = 0;
std::string s = "bar";
};
int main() {
Foo f;
ValueMonitor::watch("number", &f.x);
ValueMonitor::watch("string", &f.s);
for (int i = 0; i < 10; ++i) {
++f.x;
if (i > 5) {
f.s = "new string";
}
// print the current value of the variable with the given key
// these should change as the loop goes on
ValueMonitor::print("number");
ValueMonitor::print("string");
// or
ValueMonitor::printAll();
// obviously this would be unnecessary in this example since I
// have easy access to f, but imagine monitoring different
// values from all over a much larger code base
}
}
Then these could be easily monitored somewhere in the application's GUI or whatever.
However, I don't know how to handle the different types that would be stored in this class. Ideally, I should be able to store anything that has a string representation. I have a few ideas but none of them really seem right:
Store pointers to a superclass that defines a toString function or operator<<, like Java's Object. But this would require me to make wrappers for any primitives I want to monitor.
Something like boost::any or boost::spirit::hold_any. I think any needs to be type casted before I can print it... I guess I could try/catch casting to a bunch of different types, but that would be slow. hold_any requires defined stream operators, which would be perfect... but I can't get it to work with pointers.
Anyone have any ideas?
I found a solution somewhere else. I was pretty blown away, so might as well post it here for future reference. It looks something like this:
class Stringable
{
public:
virtual ~Stringable() {};
virtual std::string str() const = 0;
using Ptr = std::shared_ptr<Stringable>;
};
template <typename T>
class StringableRef : public Stringable
{
private:
T* _ptr;
public:
StringableRef(T& ref)
: _ptr(&ref) {}
virtual ~StringableRef() {}
virtual std::string str() const
{
std::ostringstream ss;
ss << *_ptr;
return ss.str();
}
};
class ValueMonitor
{
private:
static std::map<std::string, Stringable::Ptr> _values;
public:
ValueMonitor() {}
~ValueMonitor() {}
template <typename T>
static void watch(const std::string& label, T& ref)
{
_values[label] = std::make_shared<StringableRef<T>>(ref);
}
static void printAll()
{
for (const auto& valueItr : _values)
{
const String& name = valueItr.first;
const std::shared_ptr<Stringable>& value = valueItr.second;
std::cout << name << ": " << value->str() << std::endl;
}
}
static void clear()
{
_values.clear();
}
};
std::map<std::string, Stringable::Ptr> ValueMonitor::_values;
.
int main()
{
int i = 5;
std::string s = "test"
ValueMonitor::watch("number", i);
ValueMonitor::watch("string", s);
ValueMonitor::printAll();
i = 10;
s = "new string";
ValueMonitor::printAll();
return 0;
}
I have a code, which writes a number to std::string using std::ostringstream:
template<class T>
class Converter
{
private:
static std::string s_buffer;
public:
static const char* Out(const T& val)
{
std::ostringstream os;
os << val;
s_buffer = os.str();
return(s_buffer.data());
}
};
The Converter::Out is called a lot. So much that it even shows up in the profiler. And essentially, what happens here is:
An instance of ostringstream is created
It creates a buffer to write to and writes to it
I copy that buffer to the static string and return it
I think, that if I could get the stream to write directly to the static string, thus avoiding the copy, I may get some performance improvement. But how can I do it - std::ostringstream can accept only const std::string in constructor, which would be a preliminary fill, not the buffer to write to.
Maybe Boost has some alternative, though I didn't find one... :(
You can access the buffer of an ostringstream using the rdbuf() method; unfortunately, access to the underlying character buffer is protected. However, you can easily work around that via inheritance:
template<class T>
class Converter
{
private:
static struct Buf : public std::ostringstream, public std::basic_stringbuf<char>
{
Buf() { static_cast<std::basic_ios<char>&>(*this).rdbuf(this); }
void clear() { setp(pbase(), pbase()); }
char const* c_str() { *pptr() = '\0'; return pbase(); }
} s_buf;
public:
static const char* Out(const T& val)
{
s_buf.clear();
s_buf << val;
return s_buf.c_str();
}
};
If Boost is an option, you can use boost::iostreams::filtering_ostream backed by a string or vector<char>: http://lists.boost.org/boost-users/2012/09/75887.php
I'm implementing a very simple serialization library, to save/restore user_info object, which contains an int and a std::string, here's my code:
#include <iostream>
#include <sstream>
using namespace std;
struct user_info {
int id;
string name;
};
// for any POD type like int, read sizeof(int) from the stream
template <class stream_t, class T>
void de_serialize(stream_t& stream, T& x) {
stream.read((char*)&x, sizeof(T));
}
// for std::string, read length(int) first, then read string content when length>0
template <class stream_t>
void de_serialize(stream_t& stream, std::string& str) {
int len;
de_serialize(stream, len);
str.resize(len);
char x;
for(int i=0; i<len; i++) {
de_serialize(stream, x);
str[i] = x;
}
}
// read from stream, fill id and name
template <typename stream_t>
void de_serialize(stream_t& ss, user_info& ui) {
de_serialize(ss, ui.id);
de_serialize(ss, ui.name);
}
int main() {
// read from file, but here I use a 8-bytes-content represents the file content
stringstream ifs;
// two int, \x1\x1\x1\x1 for id, \x0\x0\x0\x0 for name
ifs.write("\x1\x1\x1\x1\x0\x0\x0\x0", 8);
while(!ifs.eof()) {
user_info ui;
de_serialize(ifs, ui);
// when first time goes here, the stream should've read 8 bytes and reaches eof,
// then break the while loop, but it doesn't
// so the second time it calls de_serialize, the program crashes
}
}
the code illustrates the part of de-serializing. The while loop is supposed to run once, and the stream reaches eof, but why it doesn't stop looping? The second loop causes a crash.
Please refer to the comments, thanks.
The eof() flag will never be set if the streem develops an error condition. It is usually wrong to loop on eof(). What I would do here is change the return type from your de_serialize() function to return the stream and then rewrite your loop around the de_serialize() function
Like this:
#include <iostream>
#include <sstream>
using namespace std;
struct user_info {
int id;
string name;
};
// for any POD type like int, read sizeof(int) from the stream
template <class stream_t, class T>
stream_t& de_serialize(stream_t& stream, T& x) {
stream.read((char*)&x, sizeof(T));
return stream; // return the stream
}
// for std::string, read length(int) first, then read string content when length>0
template <class stream_t>
stream_t& de_serialize(stream_t& stream, std::string& str) {
int len;
de_serialize(stream, len);
str.resize(len);
char x;
for(int i=0; i<len; i++) {
de_serialize(stream, x);
str[i] = x;
}
return stream; // return the stream
}
// read from stream, fill id and name
template <typename stream_t>
stream_t& de_serialize(stream_t& ss, user_info& ui) {
de_serialize(ss, ui.id);
de_serialize(ss, ui.name);
return ss; // return the stream
}
int main() {
// read from file, but here I use a 8-bytes-content represents the file content
stringstream ifs;
// two int, \x1\x1\x1\x1 for id, \x0\x0\x0\x0 for name
ifs.write("\x1\x1\x1\x1\x0\x0\x0\x0", 8);
user_info ui;
while(de_serialize(ifs, ui)) { // loop on de_serialize()
// Now you know ui was correctly read from the stream
// when first time goes here, the stream should've read 8 bytes and reaches eof,
// then break the while loop, but it doesn't
// so the second time it calls de_serialize, the program crashes
}
}
I used two design pattern Composite and Visitor. I have no problem with Composite.But when he began writing derived classes for input and output got some errors, solution which I did never found. Although in reality, and if everything is InputVisitor done so remained only PrintVisitor and main().
Here is my code:
UPD: I rewrite some parts of code. Now I have no erros, but it only open terminal and nothind doing...
P.S. Maybe I did not properly implement of patterns. Someone has a better idea?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
class BaseComponent {
public:
virtual void add(BaseComponent *)=0;
virtual void accept(class Visitor &)=0;
};
class Card :public BaseComponent {
public:
Card (string bookName, vector<string> authors, int year): _bookName(bookName), _authors(authors), _year(year) {}
string getBookName() const {
return _bookName;
}
vector<string> getAuthors() const {
return _authors;
}
int getYear() const {
return _year;
}
void setBookName(string bookName) {
_bookName = bookName;
}
void setAuthors(vector<string> authors) {
copy(authors.begin(), authors.end(), _authors.begin());
}
void setYear(int year) {
_year = year;
}
void add(BaseComponent *){}
void accept(class Visitor &);
private:
string _bookName;
vector<string> _authors;
int _year;
};
class Folder :public BaseComponent {
public:
Folder(): _folderName(""), _parentFolder("") {}
Folder(string parentFolder): _folderName(""), _parentFolder(parentFolder) {}
string getFolderName() const {
return _folderName;
}
string getParentName() const {
return _parentFolder;
}
vector<BaseComponent*> getSubFolders() const {
return _subFolders;
}
void setFolderName(string folderName) {
_folderName = folderName;
}
void setParentFolder(string parentFolder) {
_parentFolder = parentFolder;
}
void add(BaseComponent *component) {
_subFolders.push_back(component);
}
void accept(class Visitor &);
private:
string _folderName;
string _parentFolder;
vector<BaseComponent*> _subFolders;
};
class Visitor {
public:
virtual void visitCard(Card *)=0;
virtual void visitFolder(Folder *)=0;
};
void Card::accept(class Visitor &visitor) {
visitor.visitCard(this);
}
void Folder::accept(class Visitor &visitor) {
visitor.visitFolder(this);
}
class InputVisitor :public Visitor {
public:
InputVisitor(string file): _file(file){}
void setFile(string file) {
_file = file;
}
void visitCard(Card *){}
void visitFolder(Folder *folder){
ifstream input(_file);
string folderName;
getline(input, folderName);
folder->setFolderName(folderName);
string fileName;
while (!input.eof()) {
input >> fileName;
if (fileName == "----") {
break;
} else {
Folder *subFolder = new Folder(folderName);
InputVisitor *inputVisitor = new InputVisitor(fileName);
subFolder->accept(*inputVisitor);
folder->add(subFolder);
}
}
while (!input.eof()) {
string name, tempAuthor;
vector<string> authors;
int n, year;
input >> name;
input >> n;
for (int i = 0; i<n; ++i) {
input >> tempAuthor;
authors.push_back(tempAuthor);
}
input >> year;
Card *subBook = new Card(name, authors, year);
folder->add(subBook);
}
input.close();
}
private:
string _file;
};
class PrintVisitor :public Visitor {
public:
PrintVisitor(string outputFile): _outputFile(outputFile) {}
void setOutputFile(string outputFile) {
_outputFile = outputFile;
}
void visitFolder(Folder *folder) {
ofstream output(_outputFile);
output << folder->getFolderName() << endl << "\t";
vector<BaseComponent*> subFolders = folder->getSubFolders();
vector<BaseComponent*>::iterator it;
for (it=subFolders.begin(); it!=subFolders.end(); ++it) {
(*it)->accept(*this);
}
output.close();
}
void visitCard(Card *card) {
ofstream output(_outputFile);
output << "Book: " << card->getBookName() << endl
<< "Author(s): ";
vector<string> authors = card->getAuthors();
for (vector<string>::iterator it=authors.begin(); it!=authors.end(); ++it) {
output << *it << " ";
}
output << endl << "Year: " << card->getYear();
output.close();
}
private:
string _outputFile;
};
int main() {
Folder root;
root.accept(*(new InputVisitor("root.txt")));
root.accept(*(new PrintVisitor("output.txt")));
return 0;
}
In this code:
InputVisitor *input;
input->setFile("root.txt");
root->accept(input); //Here
InputVisitor is a *input. Your accept function takes a reference to a visitor. Change it to:
root->accept(*input); //Here
and all will be fine, aside from the typo I mentioned in the comment.
If you remove all the class in front of names for classes, the compiler will tell you when there is a misspelled class name. Otherwise, it will just treat it as "there'll be a class named Visirot at some point in the future, and I don't really care what's in it right now.
Here is the declaration of BaseComponent::accept:
virtual void accept(class Visirot &)=0;
Here is the call:
root->accept(input); //Here
Here is the declaration of input:
InputVisitor *input;
So, first, the declaration of BaseComponent::accept apparently has a typo; Visirot should probably be Visitor.
Second, accept takes a Visitor&, but it's being called with an InputVisitor*. InputVisitor is derived from Visitor, soInputVisitor*is convertible toVisitor*andInputVisitor&is convertible toVisitor&, but there is no conversion from a pointer-to-type into a reference-to-type. So either changeBaseComponent::accept` to take a pointer or change the call to pass a reference.
First problem.
Assuming the typo Visirot is fixed, then at line 152 you have
subFolders[i]->accept(this); //Here some probrem
which passes a pointer to T where a T is expected.
Just dereference that pointer:
subFolders[i]->accept(*this);
Second problem.
Applying the same fixes in the main program would be wrong:
int main() {
BaseComponent *root;
InputVisitor *input;
input->setFile("root.txt");
root->accept(*input); //Here
PrintVisitor *output;
output->setOutputFile("output.txt");
root->accept(output); //And here
return 0;
}
This dereferences uninitialized pointers, which yields Undefined Behavior.
Don't do that.
Rewrite it as e.g.
int main() {
Folder root;
InputVisitor input;
input.setFile("root.txt");
root.accept(input); //Here
PrintVisitor output;
output.setOutputFile("output.txt");
root.accept(output); //And here
}
(and possibly replace Folder with whatever concrete class you want there.)
Third problem.
At line 144 you're assigning to a stream:
_outputFile = ofstream(outputFile);
where _outputFile is a member of type ofstream, and outputFile is a string.
This uses a C++11 feature (rvalue assignment of streams) that g++ didn't implement as of version 4.7.1.
Presumably the idea is to close _outputFile and reopen it: just do that, and the code will be much more portable:
// Add failure checking:
_outputFile.close();
_outputFile.open( outputFile );
Also, more descriptive naming would be good…
General problem set in the given code.
Compiling the above yields a number of warnings about signed/unsigned comparisons and unused local variables. Fix all that. Build at highest practical warning level, -Wall with g++ and /W4 with Visual C++, and make it compile cleanly.
Logic errors & testing.
Even when it compiles cleanly, there can and usually will remain logic errors. To root out those, devise a set of exactly reproducible tests, complete with any necessary test data.