Boost property_tree error: conversion of data to type "j" failed when getting an element in a .ini file
Boost property_tree error: conversion of data to type "j" failed when getting an element in a .ini file
我有一个 .ini 文件包含以下数据
[SYSTEM]
num_of_vps = 1
我有这段代码可以读取 .ini 文件中的元素。 (uint
定义为 typedef unsigned int uint
)
boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini(iniFilePath, pt);
hwCount = pt.get<uint>("SYSTEM.num_of_vps");
我从包含上述代码的文件创建了一个文件,并在 main.cc
文件的包装函数中调用了它。然后我得到低于错误
terminate called after throwing an instance of 'boost_1_68_0::exception_detail::clone_impl<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> >'
what(): conversion of data to type "j" failed
stack trace
#12 0x00002aaab613fcd5 in abort () from /lib64/libc.so.6
#13 0x00002aaab9b29315 in __gnu_cxx::__verbose_terminate_handler () at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/vterminate.cc:95
#14 0x00002aaab9a9e8f6 in __cxxabiv1::__terminate (handler=<optimized out>) at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:47
#15 0x00002aaab9a9e941 in std::terminate () at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:57
#16 0x00002aaab9a9ea74 in __cxxabiv1::__cxa_throw (obj=<optimized out>, tinfo=0x2aaab9e1ff60 <typeinfo for boost_1_68_0::exception_detail::clone_impl<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> >>, dest=0x2aaab99bef18 <boost_1_68_0::exception_detail::clone_impl<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> >::~clone_impl()>) at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/eh_throw.cc:93
#17 0x00002aaab99bec82 in boost_1_68_0::throw_exception<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> > (e=...) at throw_exception.hpp:72
#18 0x00002aaab99be576 in boost_1_68_0::exception_detail::throw_exception_<boost_1_68_0::property_tree::ptree_bad_data> (x=..., current_function=0x2aaab9b45fc0 <boost_1_68_0::enable_if<boost_1_68_0::property_tree::detail::is_translator<boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int> >, unsigned int>::type boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get_value<unsigned int, boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int> >(boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int>) const::__PRETTY_FUNCTION__> "typename boost_1_68_0::enable_if<boost_1_68_0::property_tree::detail::is_translator<Translator>, Type>::type boost_1_68_0::property_tree::basic_ptree<Key, Data, KeyCompare>::get_value(T"..., file=0x2aaab9b45830 "property_tree/detail/ptree_implementation.hpp", line=675) at throw_exception.hpp:89
#19 0x00002aaab99be01e in boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get_value<unsigned int, boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int> > (this=0xbc86c8, tr=...) at property_tree/detail/ptree_implementation.hpp:673
#20 0x00002aaab99bd6a5 in boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get_value<unsigned int> (this=0xbc86c8) at property_tree/detail/ptree_implementation.hpp:683
#21 0x00002aaab99bc545 in boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get<unsigned int> (this=0x7fffffff9470, path=...) at property_tree/detail/ptree_implementation.hpp:754
#22 0x00002aaab99bba83 in MyRT::DUTConfigFile::readIniFile (this=0xbc5d50, iniFilePath=...) at DUTConfigFile.cpp:231
#23 0x00002aaab99ba8d2 in MyRT::DUTConfigFile::DUTConfigFile (this=0xbc5d50, iniFilePath=..., configFilePath=...) at DUTConfigFile.cpp:26
#24 0x00002aaab99c0839 in setupMyConfigs () at SimXLInterface.cpp:83
#31 0x0000000000408847 in main ()
我尝试了 gdb,但在使用 istringstream 将字符串转换为 uint 时抛出异常。下面是两种类型的转换
template<class K, class D, class C>
template<class Type> inline
Type basic_ptree<K, D, C>::get_value() const
{
return get_value<Type>(
typename translator_between<data_type, Type>::type());
}
(gdb) p typeid(Type).name()
= 0x2aaab5c33c91 <typeinfo name for unsigned int> "j"
(gdb) p typeid(data_type).name()
could not find typeinfo symbol for 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >'
下面 basic_ios.h
中的函数抛出一个 __throw_bad_cast()
异常(这里是 this->_M_num_get = NULL
)
const __num_get_type& __ng = __check_facet(this->_M_num_get);
内部构建自动化 Makefile 正在默认将 -D_GLIBCXX_USE_CXX11_ABI=0
添加到目标文件创建中
g++ -I/usr/myboost/boost/boost -Wall -std=c++14 -fopenmp -m64 -msse2 -fPIC \
-D_GLIBCXX_USE_CXX11_ABI=0 -g -o *.o -fPIC -c *.cpp
.so 构建命令
g++ -m64 -msse2 -pthread -shared -static-libstdc++ -static-libgcc \
-Wl,-znoexecstack -g -o runtime.so *.o -ldl -lrt -lz -fopenmp -lcrypto
如果我将其更改为读取 std::string 类型,然后将其转换为 uint,它可以正常工作
std::string strHwCount = pt.get<std::string>("SYSTEM.num_of_vps");
hwCount = static_cast<uint>(std::stoul(strHwCount));
我正在使用 boost-1.68
和 gcc-7.3
。这与我正在使用的 ABI
宏有关吗?有没有办法在没有上述解决方法的情况下解决这个问题
更新
首先,我正在将项目从 cmake 迁移到内部自定义构建自动化(Makefile 的一些增强版本)。在 cmake 中,这工作正常。根据sehe的回答,我做了一些进一步的分析。
在一个小型独立示例中,此错误不可重现(同时使用本地字符串和实际读取的 .ini 文件)。
当通过 gdb 时,在文件 boost/property_tree/stream_translator.hpp
中,我可以在 string
和 [=36] 中找到从文件中读取的值(在文件中更改为 num_of_vps = 4
) =].
optional<Type> basic_ptree<K, D, C>
::get_value_optional(Translator tr) const
{
return tr.get_value(data());
}
(gdb) p data()
= "4"
boost_1_68_0::optional<E> get_value(const internal_type &v) {
std::basic_istringstream<Ch, Traits, Alloc> iss(v);
iss.imbue(m_loc);
E e;
customized::extract(iss, e);
....
}
(gdb) p v
= "4"
(gdb) p iss.str()
= "4"
在 customized::extract(iss, e)
函数上面有一个 string
到 unsigned int
的转换,使用 basic_istream
static void extract(std::basic_istream<Ch, Traits>& s, E& e) {
s >> e;
if(!s.eof()) { s >> std::ws; }
}
在这个 >>
运算符里面有一个 _M_extract
函数,在那个 __check_facet
函数里面抛出异常(通过检查 this->_M_num_get
的 NULL)
basic_istream<_CharT, _Traits>::
_M_extract(_ValueT& __v) {
__try {
const __num_get_type& __ng = __check_facet(this->_M_num_get);
...
inline const _Facet&
__check_facet(const _Facet* __f) {
if (!__f)
__throw_bad_cast();
return *__f;
}
上述场景的堆栈跟踪
#0 std::istream::_M_extract<unsigned int>(unsigned int&) (__f=0x0) at gcc-7.3.0/objdir/x86_64-centos-linux/libstdc++-v3/include/bits/basic_ios.h:49
#1 std::istream::operator>>(unsigned int&) (this=0x7fffffff9980, __n=@0x7fffffff997c: 0)
#2 boost_1_68_0::property_tree::customize_stream::extract(std::istream&, unsigned int&) (s=..., e=@0x7fffffff997c: 0)
#3 boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int>::get_value(std::string const&) (this=0x7fffffff9b58, v="4")
我可以在我们使用的另一个地方看到相同的行为 std::stringstream
。即使 <<
运算符添加字符串
,变量 ss
也显示为空
std::stringstream ss;
ss << std::setw(8) << std::setfill('0') << std::hex << firmId;
我担心 ABI
标志会导致此问题,但我能够将其删除,但问题仍然存在。我搜索了此类 istream
问题,但找不到任何有用的信息。
您的输入已损坏。可能它使用了您没有预料到的编码或代码点,但对于人类来说并不突出 reader.
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
int main() {
std::istringstream iss(R"([SYSTEM]
num_of_vps = 1)");
boost::property_tree::ptree pt;
read_ini(iss, pt);
uint hwCount = pt.get<uint>("SYSTEM.num_of_vps");
std::cout << "hwCount: " << hwCount << "\n";
}
版画
hwCount: 1
但是,如果您将输入更改为例如
std::istringstream iss(R"([SYSTEM]
num_of_vps = 1)");
(注意 =
之后的 space 现在是 < > 160, 0, U+00A0 NO-BREAK SPACE, ^KNS,
)它打印:
版画
terminate called after throwing an instance of 'boost::wrapexcept<boost::property_tree::ptree_bad_data>'
what(): conversion of data to type "j" failed
通过对 gcc 命令的调整,我能够 运行 具有 .so
的可执行文件的所有 sstream
用法。以前 gcc 链接命令是
g++ -m64 -msse2 -pthread -shared -static-libstdc++ -static-libgcc \
-Wl,-znoexecstack -g -o runtime.so *.o -ldl -lrt -lz -fopenmp -lcrypto
删除 -static-libstdc++
并动态链接 libstdc++.so
有效
g++ -m64 -msse2 -pthread -shared -static-libgcc -Wl,-znoexecstack -o runtime.so *.o \
-fPIC -ldl -lrt -lz -fopenmp -lcrypto -Wl,-rpath,/depot/gcc-7.3.0/lib64
我有一个 .ini 文件包含以下数据
[SYSTEM]
num_of_vps = 1
我有这段代码可以读取 .ini 文件中的元素。 (uint
定义为 typedef unsigned int uint
)
boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini(iniFilePath, pt);
hwCount = pt.get<uint>("SYSTEM.num_of_vps");
我从包含上述代码的文件创建了一个文件,并在 main.cc
文件的包装函数中调用了它。然后我得到低于错误
terminate called after throwing an instance of 'boost_1_68_0::exception_detail::clone_impl<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> >' what(): conversion of data to type "j" failed stack trace
#12 0x00002aaab613fcd5 in abort () from /lib64/libc.so.6
#13 0x00002aaab9b29315 in __gnu_cxx::__verbose_terminate_handler () at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/vterminate.cc:95
#14 0x00002aaab9a9e8f6 in __cxxabiv1::__terminate (handler=<optimized out>) at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:47
#15 0x00002aaab9a9e941 in std::terminate () at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:57
#16 0x00002aaab9a9ea74 in __cxxabiv1::__cxa_throw (obj=<optimized out>, tinfo=0x2aaab9e1ff60 <typeinfo for boost_1_68_0::exception_detail::clone_impl<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> >>, dest=0x2aaab99bef18 <boost_1_68_0::exception_detail::clone_impl<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> >::~clone_impl()>) at ../../../../src/gcc-7.3.0/libstdc++-v3/libsupc++/eh_throw.cc:93
#17 0x00002aaab99bec82 in boost_1_68_0::throw_exception<boost_1_68_0::exception_detail::error_info_injector<boost_1_68_0::property_tree::ptree_bad_data> > (e=...) at throw_exception.hpp:72
#18 0x00002aaab99be576 in boost_1_68_0::exception_detail::throw_exception_<boost_1_68_0::property_tree::ptree_bad_data> (x=..., current_function=0x2aaab9b45fc0 <boost_1_68_0::enable_if<boost_1_68_0::property_tree::detail::is_translator<boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int> >, unsigned int>::type boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get_value<unsigned int, boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int> >(boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int>) const::__PRETTY_FUNCTION__> "typename boost_1_68_0::enable_if<boost_1_68_0::property_tree::detail::is_translator<Translator>, Type>::type boost_1_68_0::property_tree::basic_ptree<Key, Data, KeyCompare>::get_value(T"..., file=0x2aaab9b45830 "property_tree/detail/ptree_implementation.hpp", line=675) at throw_exception.hpp:89
#19 0x00002aaab99be01e in boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get_value<unsigned int, boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int> > (this=0xbc86c8, tr=...) at property_tree/detail/ptree_implementation.hpp:673
#20 0x00002aaab99bd6a5 in boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get_value<unsigned int> (this=0xbc86c8) at property_tree/detail/ptree_implementation.hpp:683
#21 0x00002aaab99bc545 in boost_1_68_0::property_tree::basic_ptree<std::string, std::string, std::less<std::string> >::get<unsigned int> (this=0x7fffffff9470, path=...) at property_tree/detail/ptree_implementation.hpp:754
#22 0x00002aaab99bba83 in MyRT::DUTConfigFile::readIniFile (this=0xbc5d50, iniFilePath=...) at DUTConfigFile.cpp:231
#23 0x00002aaab99ba8d2 in MyRT::DUTConfigFile::DUTConfigFile (this=0xbc5d50, iniFilePath=..., configFilePath=...) at DUTConfigFile.cpp:26
#24 0x00002aaab99c0839 in setupMyConfigs () at SimXLInterface.cpp:83
#31 0x0000000000408847 in main ()
我尝试了 gdb,但在使用 istringstream 将字符串转换为 uint 时抛出异常。下面是两种类型的转换
template<class K, class D, class C>
template<class Type> inline
Type basic_ptree<K, D, C>::get_value() const
{
return get_value<Type>(
typename translator_between<data_type, Type>::type());
}
(gdb) p typeid(Type).name()
= 0x2aaab5c33c91 <typeinfo name for unsigned int> "j"
(gdb) p typeid(data_type).name()
could not find typeinfo symbol for 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >'
下面 basic_ios.h
中的函数抛出一个 __throw_bad_cast()
异常(这里是 this->_M_num_get = NULL
)
const __num_get_type& __ng = __check_facet(this->_M_num_get);
内部构建自动化 Makefile 正在默认将 -D_GLIBCXX_USE_CXX11_ABI=0
添加到目标文件创建中
g++ -I/usr/myboost/boost/boost -Wall -std=c++14 -fopenmp -m64 -msse2 -fPIC \
-D_GLIBCXX_USE_CXX11_ABI=0 -g -o *.o -fPIC -c *.cpp
.so 构建命令
g++ -m64 -msse2 -pthread -shared -static-libstdc++ -static-libgcc \
-Wl,-znoexecstack -g -o runtime.so *.o -ldl -lrt -lz -fopenmp -lcrypto
如果我将其更改为读取 std::string 类型,然后将其转换为 uint,它可以正常工作
std::string strHwCount = pt.get<std::string>("SYSTEM.num_of_vps");
hwCount = static_cast<uint>(std::stoul(strHwCount));
我正在使用 boost-1.68
和 gcc-7.3
。这与我正在使用的 ABI
宏有关吗?有没有办法在没有上述解决方法的情况下解决这个问题
更新
首先,我正在将项目从 cmake 迁移到内部自定义构建自动化(Makefile 的一些增强版本)。在 cmake 中,这工作正常。根据sehe的回答,我做了一些进一步的分析。 在一个小型独立示例中,此错误不可重现(同时使用本地字符串和实际读取的 .ini 文件)。
当通过 gdb 时,在文件 boost/property_tree/stream_translator.hpp
中,我可以在 string
和 [=36] 中找到从文件中读取的值(在文件中更改为 num_of_vps = 4
) =].
optional<Type> basic_ptree<K, D, C>
::get_value_optional(Translator tr) const
{
return tr.get_value(data());
}
(gdb) p data()
= "4"
boost_1_68_0::optional<E> get_value(const internal_type &v) {
std::basic_istringstream<Ch, Traits, Alloc> iss(v);
iss.imbue(m_loc);
E e;
customized::extract(iss, e);
....
}
(gdb) p v
= "4"
(gdb) p iss.str()
= "4"
在 customized::extract(iss, e)
函数上面有一个 string
到 unsigned int
的转换,使用 basic_istream
static void extract(std::basic_istream<Ch, Traits>& s, E& e) {
s >> e;
if(!s.eof()) { s >> std::ws; }
}
在这个 >>
运算符里面有一个 _M_extract
函数,在那个 __check_facet
函数里面抛出异常(通过检查 this->_M_num_get
的 NULL)
basic_istream<_CharT, _Traits>::
_M_extract(_ValueT& __v) {
__try {
const __num_get_type& __ng = __check_facet(this->_M_num_get);
...
inline const _Facet&
__check_facet(const _Facet* __f) {
if (!__f)
__throw_bad_cast();
return *__f;
}
上述场景的堆栈跟踪
#0 std::istream::_M_extract<unsigned int>(unsigned int&) (__f=0x0) at gcc-7.3.0/objdir/x86_64-centos-linux/libstdc++-v3/include/bits/basic_ios.h:49
#1 std::istream::operator>>(unsigned int&) (this=0x7fffffff9980, __n=@0x7fffffff997c: 0)
#2 boost_1_68_0::property_tree::customize_stream::extract(std::istream&, unsigned int&) (s=..., e=@0x7fffffff997c: 0)
#3 boost_1_68_0::property_tree::stream_translator<char, std::char_traits<char>, std::allocator<char>, unsigned int>::get_value(std::string const&) (this=0x7fffffff9b58, v="4")
我可以在我们使用的另一个地方看到相同的行为 std::stringstream
。即使 <<
运算符添加字符串
ss
也显示为空
std::stringstream ss;
ss << std::setw(8) << std::setfill('0') << std::hex << firmId;
我担心 ABI
标志会导致此问题,但我能够将其删除,但问题仍然存在。我搜索了此类 istream
问题,但找不到任何有用的信息。
您的输入已损坏。可能它使用了您没有预料到的编码或代码点,但对于人类来说并不突出 reader.
#include <boost/property_tree/ini_parser.hpp>
#include <iostream>
int main() {
std::istringstream iss(R"([SYSTEM]
num_of_vps = 1)");
boost::property_tree::ptree pt;
read_ini(iss, pt);
uint hwCount = pt.get<uint>("SYSTEM.num_of_vps");
std::cout << "hwCount: " << hwCount << "\n";
}
版画
hwCount: 1
但是,如果您将输入更改为例如
std::istringstream iss(R"([SYSTEM]
num_of_vps = 1)");
(注意 =
之后的 space 现在是 < > 160, 0, U+00A0 NO-BREAK SPACE, ^KNS,
)它打印:
版画
terminate called after throwing an instance of 'boost::wrapexcept<boost::property_tree::ptree_bad_data>'
what(): conversion of data to type "j" failed
通过对 gcc 命令的调整,我能够 运行 具有 .so
的可执行文件的所有 sstream
用法。以前 gcc 链接命令是
g++ -m64 -msse2 -pthread -shared -static-libstdc++ -static-libgcc \
-Wl,-znoexecstack -g -o runtime.so *.o -ldl -lrt -lz -fopenmp -lcrypto
删除 -static-libstdc++
并动态链接 libstdc++.so
有效
g++ -m64 -msse2 -pthread -shared -static-libgcc -Wl,-znoexecstack -o runtime.so *.o \
-fPIC -ldl -lrt -lz -fopenmp -lcrypto -Wl,-rpath,/depot/gcc-7.3.0/lib64