boost::property_tree without exceptions - c++

I need to parse some INI files. To do this, I'm trying to use boost::property_tree, but in my system exceptions are not allowed.
How can I disable the exception support when using boost::property_tree?
If there's no way to do this, any recommendations for another library are very appreciated.
After the answer from #sehe, I tried this piece of code, but without success:
#include <iostream>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
namespace boost {
void throw_exception(std::exception const& e) {
std::cerr << "Fake exception: " << e.what() << "\n";
std::exit(255);
}
}
class Foo {
public:
bool bar(const std::string file_name) {
boost::property_tree::ptree prop_tree;
boost::property_tree::read_ini(file_name, prop_tree);
return !prop_tree.empty();
}
};
The compilation line code uses the following parameters:
-c -DBOOST_USER_CONFIG="<user.hpp>" -DBOOST_NO_EXCEPTIONS -DBOOST_EXCEPTION_DISABLE -I.\toolchain\boost -I.\include Foo.cpp
And finally, the user.hpp file:
#define BOOST_HAS_NRVO
#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION
#define BOOST_NO_CXX11_AUTO_DECLARATIONS
#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS
#define BOOST_NO_CXX11_CHAR16_T
#define BOOST_NO_CXX11_CHAR32_T
#define BOOST_NO_CXX11_CONSTEXPR
#define BOOST_NO_CXX11_DECLTYPE
#define BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
#define BOOST_NO_CXX11_DELETED_FUNCTIONS
#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
#define BOOST_NO_CXX11_FINAL
#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
#define BOOST_NO_CXX11_LAMBDAS
#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS
#define BOOST_NO_CXX11_NOEXCEPT
#define BOOST_NO_CXX11_NULLPTR
#define BOOST_NO_CXX11_RANGE_BASED_FOR
#define BOOST_NO_CXX11_RAW_LITERALS
#define BOOST_NO_CXX11_REF_QUALIFIERS
#define BOOST_NO_CXX11_RVALUE_REFERENCES
#define BOOST_NO_CXX11_SCOPED_ENUMS
#define BOOST_NO_CXX11_STATIC_ASSERT
#define BOOST_NO_CXX11_TEMPLATE_ALIASES
#define BOOST_NO_CXX11_UNICODE_LITERALS
#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
#define BOOST_NO_CXX11_USER_DEFINED_LITERALS
#define BOOST_NO_CXX11_VARIADIC_MACROS
#define BOOST_NO_CXX11_VARIADIC_TEMPLATES
#define BOOST_NO_SFINAE_EXPR
#define BOOST_NO_TWO_PHASE_NAME_LOOKUP
Some errors returned by compiler:
"boost/optional/optional.hpp", line 1047: Error: #312: no suitable user-defined conversion from "boost::bad_optional_access" to "const std::exception" exists
throw_exception(bad_optional_access());
^
"boost/property_tree/string_path.hpp", line 221: Error: #312: no suitable user-defined conversion from "boost::property_tree::ptree_bad_path" to "const std::exception" exists
BOOST_PROPERTY_TREE_THROW(ptree_bad_path("Path syntax error", *this));
^
"boost/property_tree/detail/ptree_implementation.hpp", line 78: Error: #742: namespace "boost" has no actual member "iterator_core_access"
friend class boost::iterator_core_access;
^
PS: I'm not using a widely-available standard compiler, but it's successfully compiling the boost::smart_ptr, using the same process described above.

You can configure Boost Exception to not use exceptions:
http://www.boost.org/doc/libs/1_58_0/libs/exception/doc/configuration_macros.html
You need to define BOOST_NO_EXCEPTIONS and further implement your own C-style exception handling function, like e.g.
void throw_exception(std::exception const& e) {
std::cerr << "Fake exception: " << e.what() << "\n";
std::exit(255);
}
Live On Coliru
#define BOOST_NO_EXCEPTIONS
#include <iostream>
#include <boost/property_tree/ini_parser.hpp>
namespace boost {
void throw_exception(std::exception const& e) {
std::cerr << "Fake exception: " << e.what() << "\n";
std::exit(255);
}
}
using namespace boost::property_tree;
int main() {
ptree pt;
read_ini(std::cin, pt);
write_ini(std::cout, pt.get_child("section5"));
}
Compiled with
g++ -std=c++11 -O3 -Wall -pedantic main.cpp -fno-exceptions
This prints
./test <<< "[section1]"
Fake exception: No such node (section5)

Related

GDB incomplete type forward enum : int declaration

I use a forward enum declaration in my cpp program that is causing gdb to give me an incompatible type. Here is a minimal working example:
definitions.h:
/*definitions.h*/
#ifndef DEFINITIONS_H_
#define DEFINITIONS_H_
enum ForwardEnum : int;
typedef ForwardEnum ForwardEnum;
typedef struct {
const ForwardEnum EnumValue;
} ElemConfig;
#endif //DEFINITIONS_H_
config.h:
/*config.h*/
#ifndef CONFIG_H_
#define CONFIG_H_
#include "definitions.h"
enum ForwardEnum : int {
EnumValue1 = -1,
EnumValue2,
};
#endif //CONFIG_H_
classA.h:
/*classA.h*/
#ifndef CLASSA_H_
#define CLASSA_H_
#include <array>
#include "definitions.h"
#define N_ELEMS 8
class A{
private:
const std::array<ElemConfig, N_ELEMS> Config;
public:
A(const std::array<ElemConfig, N_ELEMS>);
};
#endif //CLASSA_H_
main.cpp:
/*main.cpp*/
#include <iostream>
#include <array>
#include "definitions.h"
#include "config.h"
#include "classA.h"
const std::array<ElemConfig, N_ELEMS> AConfig {{{EnumValue1}}};
A::A(const std::array<ElemConfig, N_ELEMS> Config) : Config(Config)
{
ForwardEnum a = Config[0].EnumValue;
std::cout << a << std::endl;
};
int main(void)
{
A objectA(AConfig);
}
When I try to debug the class A constructor in gdb I get an incomplete type for the enum variable. According to this question I tried casting it to what I think is the compatible type:
print (ForwardEnum) a
When that failed I experimented to see if the problem was the typedef:
print (const enum ForwardEnum) a
And also to disassemble the constructor, but it all failed.
What is then the correct type conversion to print the content of EnumValue?
(Or, alternatively, How can I get gdb to resolve the incompatible type, while keeping the forward declaration?)
I am using gdb 7.7.1 and gcc 4.8.4
Try using print /d a.
/d means format as an integer.
See help x and help print in gdb.

Disable exception working for boost::smart_ptr but not for boost::property_tree

I'm using boost 1.57.
I need to disable exception support in my not widely-used proprietary compiler.
When I needed to use boost::smart_ptr, the following steps worked like a charm:
Disabled C++11 support using the following user.hpp file (compiling with -DBOOST_USER_CONFIG="<user.hpp>"):
#define BOOST_HAS_NRVO
#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION
#define BOOST_NO_CXX11_AUTO_DECLARATIONS
#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS
#define BOOST_NO_CXX11_CHAR16_T
#define BOOST_NO_CXX11_CHAR32_T
#define BOOST_NO_CXX11_CONSTEXPR
#define BOOST_NO_CXX11_DECLTYPE
#define BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
#define BOOST_NO_CXX11_DELETED_FUNCTIONS
#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
#define BOOST_NO_CXX11_FINAL
#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
#define BOOST_NO_CXX11_LAMBDAS
#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS
#define BOOST_NO_CXX11_NOEXCEPT
#define BOOST_NO_CXX11_NULLPTR
#define BOOST_NO_CXX11_RANGE_BASED_FOR
#define BOOST_NO_CXX11_RAW_LITERALS
#define BOOST_NO_CXX11_REF_QUALIFIERS
#define BOOST_NO_CXX11_RVALUE_REFERENCES
#define BOOST_NO_CXX11_SCOPED_ENUMS
#define BOOST_NO_CXX11_STATIC_ASSERT
#define BOOST_NO_CXX11_TEMPLATE_ALIASES
#define BOOST_NO_CXX11_UNICODE_LITERALS
#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
#define BOOST_NO_CXX11_USER_DEFINED_LITERALS
#define BOOST_NO_CXX11_VARIADIC_MACROS
#define BOOST_NO_CXX11_VARIADIC_TEMPLATES
#define BOOST_NO_SFINAE_EXPR
#define BOOST_NO_TWO_PHASE_NAME_LOOKUP
Informs boost libraries not to use exceptions: -DBOOST_NO_EXCEPTIONS -DBOOST_EXCEPTION_DISABLE
Resulting in the following compilation line: MyCOMPILER -DBOOST_USER_CONFIG="<user.hpp>" -DBOOST_NO_EXCEPTIONS -DBOOST_EXCEPTION_DISABLE -c Foo.cpp -o Foo.o
Then the following piece of code successfully compiled:
#include <iostream>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
namespace boost {
void throw_exception(std::exception const& e) {
std::cerr << "Fake exception: " << e.what() << "\n";
std::exit(255);
}
}
class Foo {
private:
boost::shared_ptr<int> ptr;
public:
bool bar(const std::string file_name) {
ptr = boost::make_shared<int>();
return true;
}
};
But when I've tried to use the above method with the following source code, the compilation goes wrong:
#include <iostream>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
namespace boost {
void throw_exception(std::exception const& e) {
std::cerr << "Fake exception: " << e.what() << "\n";
std::exit(255);
}
}
class Foo {
public:
bool bar(const std::string file_name) {
boost::property_tree::ptree prop_tree;
boost::property_tree::read_ini(file_name, prop_tree);
return !prop_tree.empty();
}
};
Resulting the following errors for instance:
"boost\boost/optional/optional.hpp", line 1047: Error: #312: no suitable user-defined conversion from "boost::bad_optional_access" to "const std::exception" exists
throw_exception(bad_optional_access());
^
"boost\boost/optional/optional.hpp", line 1055: Error: #312: no suitable user-defined conversion from "boost::bad_optional_access" to "const std::exception" exists
throw_exception(bad_optional_access());
^
"boost\boost/type_index/stl_type_index.hpp", line 138: Error: #312: no suitable user-defined conversion from "std::runtime_error" to "const std::exception" exists
boost::throw_exception(std::runtime_error("Type name demangling failed"));
^
"boost\boost/property_tree/ini_parser.hpp", line 168: Error: #540: support for exception handling is disabled; use --exceptions to enable
try {
^
Finally the question:
Why in the first case all works OK, but not in the second?
How can I get boost::property_tree to compile properly without exception support? Is this even possible?

Compiler acts as if a preprocessor directive isn't defined

I have a header file and its cpp file (Error.h, Error.cpp). The cpp file performs a check on a preprocessor directive but it always fails.
Error.h:
/*
Optional macros:
AE_EXIT_AT_ERROR
AE_CONSOLE_WRITE_AT_ERROR
*/
#pragma once
extern void aeError(const char *str, int code=1);
extern void aeAssert(bool b, const char *failStr = "assertion failed");
Error.cpp:
#include "Error.h"
#include <stdexcept>
#ifdef AE_CONSOLE_WRITE_AT_ERROR
#include <iostream>
#endif
void aeError(const char *str, int code)
{
#ifdef AE_CONSOLE_WRITE_AT_ERROR
std::cout << str << std::endl;
#endif
throw std::runtime_error(str);
#ifdef AE_EXIT_AT_ERROR
std::exit(code);
#endif
}
void aeAssert(bool b, const char *failStr)
{
if(!b)
aeError(failStr);
}
main.cpp:
//define both macros:
#define AE_CONSOLE_WRITE_AT_ERROR
#define AE_EXIT_AT_ERROR
#include "Error.h"
//rest of code
//...
both std::cout << str << std::endl; and std::exit(code); don't get compiled (I checked it "manually", although they are also marked gray by the IDE, which is VS2010).
What might be the cause of this?
main.cpp and Error.cpp are different translation units. You define the macro only for main.cpp, not for Error.cpp.
You should either put your #define directives in a header file included by both .cpp files, or define these macros in project settings/makefile.

error: ‘logFileObj’ does not name a type

I have a file named global.h whose contents are:
#define DEPTH 10
#define LOGGING //to log the progress of the program.
#ifdef LOGGING
#include <fstream>
#include <string>
extern std::string logFileName;
extern std::ofstream logFileObj;
#endif
Also main.cpp:
#include "global.h"
using namespace std;
#ifdef LOGGING
string logFileName = ".log";
ofstream logFileObj;
logFileObj.open(logFile); //line 13
logFileObj<<"depth: "<<DEPTH<<endl; //line 14
#endif
I am constantly getting the following error in compilation:
src/main.cpp:13:1: error: ‘logFileObj’ does not name a type
src/main.cpp:14:1: error: ‘logFileObj’ does not name a type
Any help appreciated.
C++ does not allow operation outside function. C++ allows you define variable globally but you need to put operations inside functions.
If I read your question correctly, you just need a function and call it when you need to:
#include <fstream>
#include <utility>
#include <string>
template<typename T>
void WriteLog(const std::string& log_file_name, const std::string& prefix, const T& data)
{
std::ofstream log_file_handler(log_file_name.c_str(), std::ios::app); // if you use C++11, you could use string directly
log_file_handler << prefix << data << std::endl;
}
usage:
WriteLog<int>("app.log", "depth:", DEPTH);

How to comment lines automatically in release mode?

I need to have some lines of code "active" in debug mode only, and ignored in release mode.
Is there a way to do something like this:
#include <iostream>
using namespace std;
#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr // cerr
#endif
int main() {
_cerr << "TEST message" << endl;
}
So that when _TEST_ is not defined, some lines are commented, or removed from the code. I know that comments are processed before the rest, so this code is wrong. But how can I get the behaviour I need without using #ifdefs explicitely?
You can use a macro for this:
#ifdef _TEST_
#define DEBUG_ONLY(x) x;
#else
#define DEBUG_ONLY(x)
#endif
int main() {
DEBUG_ONLY(cerr << "TEST message" << endl)
}
If what you are after is debug logging which is removed in release builds, you can do something like:
#ifdef _TEST_
#define LOG(x) (cerr << x << endl)
#else
#define LOG(x)
#endif
...
int main() {
LOG("TEST message");
}
Use this:
#ifdef _TEST_
#define DEBUG_TEST(x) x
#else
#define DEBUG_TEST(x)
#endif
int main() {
DEBUG_TEST(_cerr << "TEST message" << endl);
}
ifdefs are the way to go. How else would you know if the compiler is in release vs debug mode? When else besides during the preprocessing stage would that be communicated? At what other stage could you decide to remove/add code (besides during template generation). Hey maybe we can use template generation... but you still have to key off the ifdef somehow to control your template.
Maybe there's a really slick way to do this that I'm not thinking of, but everyone knows/uses ifdefs for this purpose. If you throw them a curveball its only going to drastically increase the human cost of maintaining your code.
Stick with ifdefs.
This here basically does what you are asking for:
#ifdef _TEST_
#define _cerr cerr
#else
#define _cerr if (1) {} else cerr
#endif
But don't be surprised if you for example get compiler warnings about ambiguous else if you write something like this:
if (something)
_cerr << "Why?" << std::endl;
You should always be aware of the fact that this _cerr is in fact a non-trivial macro.
Defining _cerr to nothing will fail the compilation. You could instead define a macro that you exclude while in release mode.
For example:
#ifdef _TEST_
#define LOG_ERROR(log) cerr << log << endl;
#else
#define LOG_ERROR(log)
#endif
Then in your code:
int main() {
LOG_ERROR("TEST message");
}
int main() {
#ifdef _TEST_
_cerr << "TEST message" << endl;
#endif
}
No. Absolutely, no.
Try a variation on this:
#ifdef _TEST_
ostream& _cerr = cerr;
#else
ostringstream _cerr;
#endif
(Basically you would want a stream which just discards its input.)
A nicer solution for the "no logging in release" is the following class:
class NullStream {
template<typename T> NullStream& operator<< const(T&) { }
};
Use:
#ifdef DEBUG
#define CERR std::cerr
#else
#define CERR NullStream()
#endif
Create your own NULL stream.
#include <iostream>
class NullStream {};
template<typename T>
NullStream& operator <<(NullStream& n,T const& data) {return n;}
NullStream& operator <<(NullStream& n,std::ostream& (*)(std::ostream&)) {return n;}
#ifdef _TEST_
#define myerr std::cerr
#else
NullStream myerrstream;
#define myerr myerrstream
#endif
int main()
{
myerr << "Hi" << std::endl;;
myerr << std::endl;;
}