I'm trying to parse an XML file using the boost/propert_tree library. I can get the xml file correctly and everything, but when I look for childs, it doesn't find any.
I have an input.xml file:
<ax:hello someatribute:ax="dwadawfesfjsefs">
<something>523523</something>
<ax:whatever>
<ax:service_tree>
<ax:service>some</ax:service>
<ax:url>someulr</ax:url>
</ax:service_tree>
</ax:whatever>
</ax:hello>
The function where I try to parse the xml:
void parseXml(std::istream &stream)
{
using boost::property_tree::ptree;
ptree pt;
read_xml(stream, pt);
BOOST_FOREACH(ptree::value_type const &value, pt.get_child("ax:hello"))
{
std::cout << value.first;
}
}
And the main function:
int main()
{
std::ifstream stream("input.xml");
parseXml(stream);
return 0;
}
The error message I get is:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl >'
what(): No such node (ax:hello)
Aborted (core dumped)`
As you can see, the ax:hello tag is properly opened and closed, so it should be able to find it despite the attributes, right?
Hope someone knows what's going on in here!
You're doing something else wrong/different:
Live On Coliru
#include <iostream>
#include <fstream>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
void parseXml(std::istream &stream)
{
using boost::property_tree::ptree;
ptree pt;
read_xml(stream, pt);
BOOST_FOREACH(ptree::value_type const &value, pt.get_child("ax:hello"))
{
std::cout << value.first << "\n";
}
}
int main()
{
std::istringstream stream(R"(
<ax:hello someatribute:ax="dwadawfesfjsefs">
<something>523523</something>
<ax:whatever>
<ax:service_tree>
<ax:service>some</ax:service>
<ax:url>someulr</ax:url>
</ax:service_tree>
</ax:whatever>
</ax:hello>
)");
parseXml(stream);
}
Prints
<xmlattr>
something
ax:whatever
Somewhat more elaborate dumping:
void dump(ptree const& pt, std::string const& indent = "") {
for (auto& node : pt) {
std::cout << indent << node.first;
auto value = boost::trim_copy(node.second.get_value(""));
if (!value.empty())
std::cout << ": '" << value << "'";
std::cout << "\n";
dump(node.second, indent + " ");
}
}
Prints Live On Coliru too
ax:hello
<xmlattr>
someatribute:ax: 'dwadawfesfjsefs'
something: '523523'
ax:whatever
ax:service_tree
ax:service: 'some'
ax:url: 'someulr'
Related
Properly testing function return values is fundamental, but it can quickly clutter the code and make it hard to read, like in the simple example below:
#include <iostream>
#include <fstream>
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
std::ifstream ifs(filename.c_str());
if (!ifs.is_open())
{
std::cerr << "Failed to open file " << filename << std::endl;
return 1;
}
ifs.close();
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
ifs.open(filename.c_str());
if (!ifs.is_open())
{
std::cerr << "Failed to open file " << filename << std::endl;
return 1;
}
return 0;
}
I have thought of a solution reducing cluttering by using a macro and c++11 lambda functions like this:
#include <iostream>
#include <fstream>
#define RETURN_IF(X,Y,Z) if ( X ) { Y ; return Z; }
auto open_file_error = [](const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
};
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
std::ifstream ifs(filename.c_str());
RETURN_IF (!ifs.is_open(), open_file_error(filename), 1 );
ifs.close();
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
ifs.open(filename.c_str());
RETURN_IF (!ifs.is_open(), open_file_error(filename), 1 );
return 0;
}
As you can see, the main function is less cluttered. Do you think that there are drawbacks to doing it like that or could it be a method to largely use?
Note that I use several macros to handle cases with or without a return value, for testing equality with a value, etc.
I propose the new version below to take into account two things:
- the answers and comments about the preference on using exceptions instead of return values;
- put away the emphasis on std::ifstream specific errors which are not the subject of the question.
#include <iostream>
#include <fstream>
#include <exception>
class OurExceptionForTheExternalLibraryFailure : public std::exception {};
#define CLEANUP_AND_THROW_IF(X,Y,Z) if ( X ) { Y ; throw Z; }
/* Return true in case of succes and false otherwise */
bool anyExternalFunction(const std::string& aString)
{
std::ifstream ifs(aString.c_str());
if (ifs.is_open())
{
ifs.close();
return true;
}
else
{
return false;
}
}
auto this_external_function_error_cleanup = [](const std::string& aString)
{
std::cerr << "The external function failed " << aString << std::endl;
// other stuff
};
int main(int argc, char **argv)
{
try
{
std::string aString = "/usr/include/malloc.h";
bool functionResult = anyExternalFunction(aString);
CLEANUP_AND_THROW_IF (!functionResult, this_external_function_error_cleanup(aString), OurExceptionForTheExternalLibraryFailure() );
std::cout << "Passed the first error handling" << std::endl;
aString = "/this/file/does/not/exist";
functionResult = anyExternalFunction(aString);
CLEANUP_AND_THROW_IF (!functionResult, this_external_function_error_cleanup(aString), OurExceptionForTheExternalLibraryFailure() );
}
catch (const OurExceptionForTheExternalLibraryFailure& e)
{
std::cerr << "Catched OurExceptionForTheExternalLibraryFailure. There was an error" << std::endl;
}
return 0;
}
What do you think about this new version (which still uses a macro, though...) ?
Well, if you are already using lambdas, and you don't want all that testing code everywhere, you could always do something like (NOTE: uncompiled/untested code,)
template <typename FileReader>
void with_file(std::string file, FileReader&& reader) {
std::ifstream in(file);
if (in) {
reader(in);
} else {
throw std::runtime_error("Failed to open file: " + file); // NOTE: I'm being lazy here
}
}
int main(...) {
with_file("foo.txt", [](auto& in) {
// do something with the stream
});
}
.. but it's a matter of preference, I like exceptions, lambdas and small utility functions, but some may not...
This is pretty much a textbook example of when to use exceptions.
You don't, however, have to write your own code to test for a file opening correctly, and throwing an exception (and so on) when it fails. Iostreams already support that fairly directly, so you can write code something like this:
#include <fstream>
#include <iostream>
int main() {
try {
std::ifstream in("/usr/include/malloc.h");
in.exceptions(std::ios::failbit);
in.close();
std::cout << "passed first test.\n";
std::ifstream in2("/this/file/does/not/exist");
in2.exceptions(std::ios::failbit);
in2.close();
std::cout << "Passed second test\n";
}
catch (std::system_error &f) {
std::cerr << "Failed to open file: " << f.what() << "\n";
}
}
Of course, if you want to get the try/catch out of main, you can do that as well. I'm not sure you gain much from doing so though.
More generally, however, exceptions are clearly the right tool for this job. For other functions that don't provide a way to get exceptions reported as exceptions, you may have to write a wrapper of your own. Either way, however, if you have a function that has some range of normal return values, and one (or a few) "special" values in indicate failure (and similar) that's a pretty decent indication that it's indicating an exceptional condition via the return value--and the right way to deal with exceptional conditions is via exceptions rather than return values.
Rather than try to reiterate the (long) list of why/when/how to use exception handling, I'll refer you (as a starting point) to Herb Sutter's old article on when and how to use exceptions.
Suggest this as a much cleaner example. NOW USING EXCEPTIONS...
I haven't tested that it's 100% the same behaviour as your example (which I appreciate is just that; an example).
By the way, MFC has a "SUCCESS" macro that does a similar check to your "RETURN_IF". I don't like that macro either...
#include <iostream>
#include <fstream>
#include <string>
void TestForFileOpen(const std::string& filename)
{
std::ifstream ifs(filename.c_str());
if (!ifs.is_open())
{
throw std::exception("Failed");
}
}
void ReportFileOpenFailure(const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
}
void NoisyTestForFileOpen(const std::string& filename)
{
try
{
TestForFileOpen(filename);
}
catch(...)
{
ReportFileOpenFailure(filename);
throw;
}
}
int main(int argc, char **argv)
{
std::string filename("/usr/include/malloc.h");
try
{
NoisyTestForFileOpen(filename);
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
NoisyTestForFileOpen(filename);
}
catch (...)
{
return 1;
}
return 0;
}
A more general example with a custom API:
#include <iostream>
#include <fstream>
#include <string>
class IFileTester
{
public:
virtual ~IFileTester() {}
// throws if file cannot be opened
virtual void TestForFileOpen(const std::string& filename) const = 0;
};
class IfStreamFileTester : public IFileTester // implement as many versions as you need
{
public:
virtual void TestForFileOpen(const std::string& filename) const
{
// implement this in terms of ifstream
std::ifstream ifs(filename.c_str());
// thanks #Jerry-Coffin
ifs.exceptions(std::ios::failbit);
}
};
void ReportFileOpenFailure(const std::string& filename)
{
std::cerr << "Failed to open file " << filename << std::endl;
}
void NoisyTestForFileOpen(const IFileTester& fileTester, const std::string& filename)
{
try
{
fileTester.TestForFileOpen(filename);
}
catch(...)
{
ReportFileOpenFailure(filename);
throw;
}
}
int main(int argc, char **argv)
{
IFileTester& fileTester = IfStreamFileTester();
std::string filename("/usr/include/malloc.h");
try
{
NoisyTestForFileOpen(fileTester, filename);
std::cout << "Passed the first error handling" << std::endl;
filename = "/this/file/does/not/exist";
NoisyTestForFileOpen(fileTester, filename);
}
catch (...)
{
return 1;
}
return 0;
}
Looks okay to me. I wouldn't put all your eggs into this basket because you don't have to make it much more complicated to run into limitations with preprocessor syntax but, as it is, this is fine.
okay, so I am banging my head on this for last couple of days but still I am unable to get it right. I have a std::list container and I want to serialize it into JSON string so that I can send it over network.
NOTE: I compile my code using following:
g++ -std=c++11 -o main main.cpp DBAccess11.cpp -lsqlite3 -lboost_serialization
I took help of this and this
Below is my DBAccess1.h file.
#ifndef DBAccess1_HH
#define DBAccess1_HH
#include <list> // I have deleted some header for sake of readability
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace std;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
//================================//
struct SiteCode
{
int siteID;
int siteCode;
};
inline ostream& operator<< (ostream &out, SiteCode &site)
{
out << "(" << site.siteID << "," << site.siteCode << ")";
return out;
}
//================================//
class sqliteDB {
list<SiteCode> Site_Code_list;
public:
list<SiteCode> GET_ALL_Site_Code();
void printList();
};
#endif**
Below is the DBAccess11.cpp file where all the functions are defined
#include <list> // I have deleted some header for sake of readability
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/serialization/list.hpp>
#include "DBAccess1.h"
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
list<SiteCode> sqliteDB::GET_ALL_Site_Code()
{
sqlite3 *db;
const char *sql;
sqlite3_stmt * stmt;
int rc = sqlite3_open("/path/to/database.db", &db);
sql = "SELECT * FROM SiteCode;";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
while(sqlite3_step(stmt)==SQLITE_ROW) {
int A = sqlite3_column_int(stmt, 0);
int B = sqlite3_column_int(stmt, 1);
SiteCode info;
info.siteID = A;
info.siteCode = B;
cout<<"Preparing to push data into List"<<endl;
Site_Code_list.push_back(info);
cout<<"Data was pushed successfully"<<endl;
ptree pt;
for (auto& entry: list<SiteCode> Site_Code_list) //<< ERROR LINE80
pt.put(entry.siteID, entry.siteCode);
std::ostringstream buf;
write_json (buf, pt, false);
cout<< buf.str() << endl;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return Site_Code_list;
}
//====================================================//
void sqliteDB::printList()
{
int s = Site_Code_list.size();
cout << "The size of List is :" << s << endl;
for( list<SiteCode> :: iterator it = Site_Code_list.begin(); it != Site_Code_list.end(); it++)
cout << *it << " ";
}
Below is main.cpp
#include <list> // I have deleted some header for sake of readability
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace std;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
int main()
{
sqliteDB object1;
object1.GET_ALL_Site_Code();
object1.printList();
cout << "\n\nAll the statement were executed properly\n\n";
return 0;
}
The error I get is as follows:
DBAccess11.cpp: In member function ‘std::list<SiteCode> sqliteDB::GET_ALL_Site_Code()’:
DBAccess11.cpp:80:38: error: expected primary-expression before ‘Site_Code_list’
for (auto& entry: list<SiteCode> Site_Code_list)
^
DBAccess11.cpp:80:38: error: expected ‘)’ before ‘Site_Code_list’
DBAccess11.cpp:80:52: error: expected ‘;’ before ‘)’ token
for (auto& entry: list<SiteCode> Site_Code_list)
^
My Questions:
(1)Is this the right way to convert std::list into JSON using boost ? if NO then how should it be done ?
(Note- I can only use boost and no other library )
(2) If my approach is right then what changes shall I make to correct it ?
Paths in your tree are always strings. The compiler will tell you this in the remainder of the message. Arguably the documentation is a more readable source:
Both key_type and data_type are configurable, but will usually be std::string here
The self_type & put(const path_type & path, const Type & value, Translator tr);
So the essence of the fix is
pt.put(std::to_string(entry.id), entry.code);
I got a little bit side-tracked cleaning up the code, so here goes:
Self Contained Sample
// FILE: some header
#include <ostream>
struct SiteCode {
int id;
int code;
SiteCode(int id, int code) : id(id), code(code)
{ }
friend inline std::ostream &operator<<(std::ostream &out, SiteCode const& site) {
return out << "(" << site.id << "," << site.code << ")";
}
};
#include <list> // I have deleted some header for sake of readability
// FILE: sqliteDB header
class sqliteDB {
using Records = std::list<SiteCode>;
Records _records;
public:
void load();
Records const& get() const { return _records; }
void printList() const;
void writeJson(std::ostream& os) const;
};
// FILE: some sqlpp.hpp utility header (inline implementations only)
#include <memory>
#include <sqlite3.h>
namespace sqlpp {
using database = std::shared_ptr<::sqlite3>;
void perror(int rc) {
if (rc != SQLITE_OK) throw std::runtime_error(::sqlite3_errstr(rc));
}
struct statement {
static statement prepare(database db, std::string const& sql) {
::sqlite3_stmt* stmt = nullptr;
perror(::sqlite3_prepare_v2(db.get(), sql.c_str(), -1, &stmt, 0));
return { handle(stmt, ::sqlite3_finalize), db };
}
int step() { return ::sqlite3_step(_stmt.get()); }
int column_int(int c) { return ::sqlite3_column_int(_stmt.get(), c); }
private:
using handle = std::shared_ptr<::sqlite3_stmt>;
database _db; // keeping it around for the lifetime of _stmt
handle _stmt;
statement(handle&& h, database& db) : _db(db), _stmt(std::move(h)) { }
};
database open(char const* path) {
::sqlite3* db = nullptr;
perror(::sqlite3_open(path, &db));
return database(db, ::sqlite3_close);
}
statement prepare(database db, std::string const& sql) {
return statement::prepare(db, sql);
}
}
// FILE: sqliteDB implementation file
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
void sqliteDB::load() {
using namespace sqlpp;
auto stmt = prepare(open("/tmp/database.db"), "SELECT ID, CODE FROM SiteCode;");
while (stmt.step() == SQLITE_ROW)
_records.emplace_back(stmt.column_int(0), stmt.column_int(1));
}
void sqliteDB::writeJson(std::ostream& os) const {
using namespace boost::property_tree;
ptree pt;
for (auto &entry : _records)
pt.put(std::to_string(entry.id), entry.code);
write_json(os, pt, false);
}
// FILE: main program
template <typename List>
static void printList(List const& list) {
int s = list.size();
std::cout << "The number of Records is: " << s << "\n";
for (auto& r : list) std::cout << r << " ";
}
void dump(sqliteDB const& db) {
printList(db.get());
std::cout << "\n==============[ AS JSON ]===============\n";
db.writeJson(std::cout);
}
int main() {
sqliteDB db;
std::cout << "before loading: \n";
dump(db);
std::cout << "after loading: \n";
db.load();
dump(db);
}
Just compile as g++ -std=c++11 -g -Wall -Wextra -pedantic main.cpp -lsqlite3 and get:
sehe#desktop:/tmp$ sqlite3 database.db <<< "create table SiteCode (id int primary key, code int);"
sehe#desktop:/tmp$ for a in {1..10}; do echo "insert into SiteCode(ID,CODE) VALUES($a, $RANDOM);"; done | sqlite3 database.db
sehe#desktop:/tmp$ ./test
Output
before loading:
The number of Records is: 0
==============[ AS JSON ]===============
{}
after loading:
The number of Records is: 10
(1,5591) (2,31578) (3,30641) (4,4850) (5,1628) (6,5133) (7,8798) (8,20601) (9,21213) (10,18222)
==============[ AS JSON ]===============
{"1":"5591","2":"31578","3":"30641","4":"4850","5":"1628","6":"5133","7":"8798","8":"20601","9":"21213","10":"18222"}
ok so working on the solution provide above by sehe. i finally able to get the output right. I had to modify his solution as per my need. here the answer is as per below. All credit and thanks to sehe.
Below is my DBAccess1.h file:
#ifndef DBAccess1_HH
#define DBAccess1_HH
#include <sqlite3.h>
#include <list>
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace std;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
//=========================//
struct SiteCode
{
int siteID;
int siteCode;
friend inline std::ostream &operator<<(std::ostream &out, SiteCode const& site) {
return out << "(" << site.siteID << "," << site.siteCode << ")";
}
};
//=========================//
class sqliteDB {
using Records = std::list<SiteCode>;
Records Site_Code_list;
public:
list<SiteCode> GET_ALL_Site_Code();
Records const& get() const { return Site_Code_list; }
void writeJson(std::ostream& os) const;
void printList() const;
};
#endif
Below is DBAccess11.cpp
#include <ostream>
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "DBAccess1.h"
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
list<SiteCode> sqliteDB::GET_ALL_Site_Code()
{
sqlite3 *db;
const char *sql;
sqlite3_stmt * stmt;
int rc = sqlite3_open("/path.to/database.db", &db);
sql = "SELECT * FROM SiteCode;";
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
while(sqlite3_step(stmt)==SQLITE_ROW) {
int A = sqlite3_column_int(stmt, 0);
int B = sqlite3_column_int(stmt, 1);
SiteCode info;
info.siteID = A;
info.siteCode = B;
cout<<"Preparing to push data into List"<<endl;
Site_Code_list.push_back(info);
cout<<"Data was pushed successfully"<<endl;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return Site_Code_list;
}
//==============================================================//
void sqliteDB::writeJson(std::ostream& os) const
{
using namespace boost::property_tree;
ptree pt;
for (auto &entry : Site_Code_list)
pt.put(std::to_string(entry.siteID), entry.siteCode);
write_json(os, pt, false);
}
//=========================================================//
Below is main.cpp
#include <ostream>
#include <boost/serialization/list.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "DBAccess1.h"
using namespace std ;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
template <typename List>
static void printList(List const& list) {
int s = list.size();
std::cout << "The number of Records is: " << s << "\n";
for (auto& r : list) std::cout << r << " ";
}
void dump(sqliteDB const& db) {
printList(db.get());
std::cout << "\n==============[ AS JSON ]===============\n";
db.writeJson(std::cout);
}
int main()
{
sqliteDB object1;
std::cout << "before loading: \n";
dump(object1);
std::cout << "after loading: \n";
object1.GET_ALL_Site_Code();
dump(object1);
return 0;
}
compiled the above using:
g++ -std=c++11 -o main main.cpp DBAccess11.cpp -lsqlite3 -lboost_serialization
And the following is the output I get:
before loading:
The number of Records is: 0
==============[ AS JSON ]===============
{}
after loading:
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
Preparing to push data into List
Data was pushed successfully
The number of Records is: 10
(7,786) (8,78) (9,785) (10,998) (11,656) (13,23) (14,7) (15,74) (16,954) (17,752)
==============[ AS JSON ]===============
{"7":"786","8":"78","9":"785","10":"998","11":"656","13":"23","14":"7","15":"74","16":"954","17":"752"}
I read about substr from here
http://www.cplusplus.com/reference/string/string/substr/
Here is my code :
int main()
{
std::ifstream in ("c:\\users\\admin\\desktop\\aaa.txt");
std::ofstream out ("c:\\users\\admin\\desktop\\bbb.txt");
std::string s ;
while ( getline (in,s) )
{
std::size_t startpos = s.find("test");
std::string str = s.substr (startpos);
out << str << endl;
}
in.close();
out.close();
}
I get error : R6010 abort() has been called
Note : aaa.txt contains spaces/characters/html tags
Any idea ?
Since I dont know the content of the text file, could you try making the following changes and let me know if the error is still being shown:
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
ifstream in("example.txt");
ofstream out("bbb.txt");
string s = std::string();
string str = std::string();
while (getline(in, s))
{
size_t startpos = s.find("test");
cout << s;
if (startpos != std::string::npos){
str = s.substr(startpos);
out << str << endl;
}
}
in.close();
out.close();
getchar();
return 0;
}
I am using if (startpos != std::string::npos) condition to check what to do when the find succeeds, this is missing in your code. adding this case will resolve your error.
Keep coding :)
While Code Frenzy answer is right, you can also use exceptions to help catch these kind of errors:
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
std::ifstream in ("aaa.txt");
std::ofstream out ("bbb.txt");
std::string s ;
try
{
while ( getline (in,s) )
{
std::size_t startpos = s.find("test");
std::string str = s.substr (startpos);
out << str << endl;
}
in.close();
out.close();
}
catch(std::exception e)
{
// (1) it will catch the error show show
cerr << e.what() << endl;
}
catch(std::out_of_range e)
{
// (2) this will also catch the same error if (1) was not there but could
// get you more details if you wanted since its more specific but i have
// not digged into it further
cerr << e.what() << endl;
}
catch(...)
{
// (3) just for sanity check if first two didn't catch it
cerr << "something went wrong";
}
}
The exceptoin catches this error and prints the message:
invalid string position
I've been trying to store the lines of a text file in a list in C++. Better, I've been trying to store each word of each line of the text file in a string that is part of a list of strings, but it seems that I'm doing it in the wrong way.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <list>
using namespace std;
int main()
{
FILE *f= fopen("teste.txt", "r");
size_t len= 100; // valor arbitrário
char *line= (char*)malloc(len);
std::list<string> mylist;
if (!f)
{
perror("teste.txt");
exit(1);
}
while (getline(&line, &len, f) > 0)
{ //THE REAL PROBLEM
for (std::list<string>::iterator it = mylist.begin(); it != mylist.end(); it++){
*it=line;
cout << *it << '\n';
}
}
if (line)
free(line);
fclose(f);
return 0;
}
The exact problem is that this doesn't give any result. It compiles but nothing results from this.
Thanks in advance.
Change your while loop as follows:
while (getline(&line, &len, f) > 0)
{
mylist.push_back(line);
cout << mylist.back() << '\n';
}
You cannot access any non initialized items from a std::list<>.
Also NOTE you should make line a std::string, and omit the malloc() / free() calls from your code.
2nd NOTE: Use std::ifstream instead of FILE* for an input file stream.
Here's the fully fixed (no more errors/exceptions on ideone) code sample:
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <exception>
#include <errno.h>
#include <stdlib.h>
int main()
{
try
{
std::ifstream f("teste.txt");
if(!f)
{
std::cerr << "ERROR: Cannot open 'teste.txt'!" << std::endl;
exit(1);
}
std::string line;
std::list<std::string> mylist;
while (std::getline(f,line))
{
mylist.push_back(line);
std::cout << mylist.back() << std::endl;
}
}
catch(const std::exception& ex)
{
std::cerr << "Exception: '" << ex.what() << "'!" << std::endl;
exit(1);
}
exit(0);
}
You can not assign a char* value to std::string by using '=' operator.
Change
*it=line to
it->assign(line,line+strlen(line);
I got this code form the boost library.
http://www.boost.org/doc/libs/1_42_0/doc/html/boost_propertytree/tutorial.html
This is the xml file they have
<debug>
<filename>debug.log</filename>
<modules>
<module>Finance</module>
<module>Admin</module>
<module>HR</module>
</modules>
<level>2</level>
</debug>
The code to load these values and print them is
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <set>
#include <exception>
#include <iostream>
struct debug_settings
{
std::string m_file; // log filename
int m_level; // debug level
std::set<std::string> m_modules; // modules where logging is enabled
void load(const std::string &filename);
void save(const std::string &filename);
};
void debug_settings::load(const std::string &filename)
{
using boost::property_tree::ptree;
ptree pt;
read_xml(filename, pt);
m_file = pt.get<std::string>("debug.filename");
m_level = pt.get("debug.level", 0);
BOOST_FOREACH(ptree::value_type &v, pt.get_child("debug.modules"))
m_modules.insert(v.second.data());
}
void debug_settings::save(const std::string &filename)
{
using boost::property_tree::ptree;
ptree pt;
pt.put("debug.filename", m_file);
pt.put("debug.level", m_level);
BOOST_FOREACH(const std::string &name, m_modules)
pt.put("debug.modules.module", name,true);
write_xml(filename, pt);
}
int main()
{
try
{
debug_settings ds;
ds.load("debug_settings.xml");
ds.save("debug_settings_out.xml");
std::cout << "Success\n";
}
catch (std::exception &e)
{
std::cout << "Error: " << e.what() << "\n";
}
return 0;
}
But it gives me an error
/usr/include/boost/property_tree/detail/ptree_implementation.hpp:769: error: request for member ‘put_value’ in ‘tr’, which is of non-class type ‘bool’
Can anyone tell me what I am missing?
Seems they have replaced the put () function ... So if I changed the line
"pt.put("debug.modules.module", name,true);"
to
"pt.add("debug.modules.module", name);"
it works fine. Thank you.