C++ 满足Nan和Inf时boost序列化1.5.5崩溃

C++ 满足Nan和Inf时boost序列化1.5.5崩溃,c++,boost,boost-serialization,C++,Boost,Boost Serialization,boost序列化似乎无法从基于文本的存档中恢复值Nan和inf 除非您处理archive\u异常,否则程序将终止。在这种情况下,有任何解决方案吗?库的作者: 简单的事实是我从来没有考虑过这个问题。 上次提到这个问题时,我并没有像我想象的那样认真思考 我还参与了其他事情,我希望有兴趣的各方能达成一致 达成共识,而不必弯曲过度伸展的大脑 (继续讨论解决办法) 这似乎是正确的,在我的测试中,只有二进制文件支持inf/nan 除了nan/inf之外,Xml和文本存档确实支持全部精度: using BI

boost序列化似乎无法从基于文本的存档中恢复值Nan和inf

除非您处理
archive\u异常,否则程序将终止。在这种情况下,有任何解决方案吗?

库的作者:

简单的事实是我从来没有考虑过这个问题。 上次提到这个问题时,我并没有像我想象的那样认真思考 我还参与了其他事情,我希望有兴趣的各方能达成一致 达成共识,而不必弯曲过度伸展的大脑

(继续讨论解决办法)

这似乎是正确的,在我的测试中,只有二进制文件支持inf/nan

除了nan/inf之外,Xml和文本存档确实支持全部精度:

using BIA = boost::archive::binary_iarchive;
using BOA = boost::archive::binary_oarchive;
using TIA = boost::archive::text_iarchive;
using TOA = boost::archive::text_oarchive;
using XIA = boost::archive::xml_iarchive;
using XOA = boost::archive::xml_oarchive;

int main() {

    // supported:
    assert((perform_test<BIA,  BOA, use_nan, use_inf, use_range>()));
    assert((perform_test<XIA,  XOA, no_nan,  no_inf,  use_range>()));
    assert((perform_test<TIA,  TOA, no_nan,  no_inf,  use_range>()));

    // not supported:
    assert(!(perform_test<XIA, XOA, no_nan,  use_inf>()));
    assert(!(perform_test<TIA, TOA, no_nan,  use_inf>()));

    assert(!(perform_test<XIA, XOA, use_nan, no_inf>()));
    assert(!(perform_test<TIA, TOA, use_nan, no_inf>()));

}
使用BIA=boost::archive::binary\u iarchive;
使用BOA=boost::archive::binary\u oarchive;
使用TIA=boost::archive::text\u iarchive;
使用TOA=boost::archive::text\u oarchive;
使用XIA=boost::archive::xml\u iarchive;
使用XOA=boost::archive::xml\u oarchive;
int main(){
//支持:
断言((perform_test());
断言((perform_test());
断言((perform_test());
//不支持:
断言(!(执行测试());
断言(!(执行测试());
断言(!(执行测试());
断言(!(执行测试());
}
完整列表 为子孙后代:

#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <sstream>

using namespace boost::archive;

static bool equal_or_nan(double a, double b) {
    return (std::isnan(a) && std::isnan(b)) || a==b;
}

template <typename IA, typename OA, 
         bool withNan   = true,
         bool withInf   = true,
         bool withRange = true>
bool perform_test() 
{
    std::vector<double> const v {
        withRange? std::numeric_limits<double>::min()       : 0,
        withRange? std::numeric_limits<double>::max()       : 0,
        withRange? std::numeric_limits<double>::epsilon()   : 0,
        withNan?   std::numeric_limits<double>::quiet_NaN() : 0,
        withInf?   std::numeric_limits<double>::infinity()  : 0,
        withInf? - std::numeric_limits<double>::infinity()  : 0,
    };

    std::stringstream ss;
    {
        OA oa(ss);
        oa << boost::serialization::make_nvp("element", v);
    }

    try
    {
        IA ia(ss);
        std::vector<double> w;
        ia >> boost::serialization::make_nvp("element", w);

        return std::equal(v.begin(), v.end(), w.begin(), equal_or_nan);
    } catch(...) {
        return false;
    }
}

static constexpr bool use_inf = true, use_nan = true, use_range = true;
static constexpr bool no_inf  = false, no_nan = false, no_range = false;

using BIA = boost::archive::binary_iarchive;
using BOA = boost::archive::binary_oarchive;
using TIA = boost::archive::text_iarchive;
using TOA = boost::archive::text_oarchive;
using XIA = boost::archive::xml_iarchive;
using XOA = boost::archive::xml_oarchive;

int main() {

    // supported:
    assert((perform_test<BIA,  BOA, use_nan, use_inf, use_range>()));
    assert((perform_test<XIA,  XOA, no_nan,  no_inf,  use_range>()));
    assert((perform_test<TIA,  TOA, no_nan,  no_inf,  use_range>()));

    // not supported:
    assert(!(perform_test<XIA, XOA, no_nan,  use_inf>()));
    assert(!(perform_test<TIA, TOA, no_nan,  use_inf>()));

    assert(!(perform_test<XIA, XOA, use_nan, no_inf>()));
    assert(!(perform_test<TIA, TOA, use_nan, no_inf>()));

}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间boost::archive;
静态布尔等于或等于(双a,双b){
返回(std::isnan(a)和&std::isnan(b))|a==b;
}
模板
布尔执行测试()
{
向量常数v{
withRange?std::numeric_limits::min():0,
withRange?std::numeric_limits::max():0,
withRange?std::numeric_limits::epsilon():0,
withNan?std::numeric_limits::quiet_NaN():0,
withInf?std::numeric_limits::infinity():0,
withInf?-std::数值限制::无穷大():0,
};
std::stringstream-ss;
{
OA(ss);
oa>boost::serialization::make_nvp(“元素”,w);
返回std::equal(v.begin()、v.end()、w.begin()、equal_或_nan);
}捕获(…){
返回false;
}
}
静态constexpr bool use\u inf=true,use\u nan=true,use\u range=true;
静态constexpr bool no_inf=false、no_nan=false、no_range=false;
使用BIA=boost::archive::binary\u iarchive;
使用BOA=boost::archive::binary\u oarchive;
使用TIA=boost::archive::text\u iarchive;
使用TOA=boost::archive::text\u oarchive;
使用XIA=boost::archive::xml\u iarchive;
使用XOA=boost::archive::xml\u oarchive;
int main(){
//支持:
断言((perform_test());
断言((perform_test());
断言((perform_test());
//不支持:
断言(!(执行测试());
断言(!(执行测试());
断言(!(执行测试());
断言(!(执行测试());
}

看一下主题。boost/math/special_函数(参见问题)中有一些方面,以及应用它们的方法(参见答案)。

辅助模板函数或重载运算符(例如boost::serialization::make_nvp(nvp.name(),iStr); 如果(iStr==nanCStr)nvp.value()=nan; else nvp.value()=std::stod(iStr); 返回ia; } 静态boost::archive::xml\u oarchive& 流(boost::archive::xml\u oarchive&oa、, 常量boost::序列化::nvp和nvp) { if(std::isnan(nvp.value())){ std::string nanStr=nanCStr;
oa首先,这不是boost archives特有的问题,它是iostream的一个功能,即文本流。您可以流式输出NaN值,但无法读回。我甚至不确定NaN将如何打印

如果您要“修补”boost库,那么可以在

boost/archive/basic_text_iprimitive.hpp

template< class IStream >
class basic_text_iprimitive
然后,您可以在阅读以下内容之前将其注入您的流:

is.imbue( infLocale )
(您也可以在第一次加载和读取XML时进行嵌入,如果只有一个库用于读取XML,那么就这样做,但是如果您在代码中的不同位置进行嵌入,那么这样做并不理想)


当然,为了确保一致性,您需要使用类似的区域设置来编写NAN。boost为此提供了一个nonfinite_num_put方面。您可以将其与nonfinite_num_get放在同一区域设置中,然后在创建XML文件句柄或专门化模板方法时将其嵌入到流中。

需要一个小的复制程序。另外,yo你没有提到版本、存档类型等。在有效的情况下,在boost Trackers报告错误。我看了一下。一个简单的boost::optional就足够了吗?假设你不想区分NAN,只想在你的存档中将所有NAN存储为null。@CashCow-Heh。如果你不想存储它们,就不要存储它们。Optional是有效的,但它并不“足够”回答本问答的主题。(例如,为了避免头痛,停止进食一周就足够了。)如果你碰巧在boost property_树中有这些NAN,你就无法控制如何将其写入XML。它有效吗?@CashCow什么?不,没有。这就是重点。但是你的“解决方案”似乎只是“那就别那么做”。没有NaN并不能解决拥有NaN的问题。它只是否认问题。这个问题是问是否可以做到,答案是否定的。消除问题是一个解决办法。存在许多解决办法。这能解决问题吗?这当然是一个补丁,boost应该自己解决,但它可能很有效。@CashCow我们使用它指定特定类型应如何序列化是一种通用解决方案。@CashCow在上面的
double
示例中,调用流函数,如
stream(ar,boost::serialization::make_nvp(“double_var_name”,double_var_value))
。另外请注意,我们使用的是
nanCStr
=
“NaN”字符串表示南号。它可以被更改为<代码>“NANN”<代码>,使它更符合C++流。实际上我用我的解决方案解决了它。
template <>
class StreamSelector<double> {
 public:
  constexpr static double nan = std::numeric_limits<double>::quiet_NaN();
  constexpr static const char* nanCStr = "nan";

  static boost::archive::xml_iarchive&
  stream(boost::archive::xml_iarchive& ia,
         const boost::serialization::nvp<double>& nvp)
  {
    std::string iStr;
    ia >>  boost::serialization::make_nvp(nvp.name(), iStr);
    if(iStr == nanCStr) nvp.value() = nan;
    else nvp.value() = std::stod(iStr);

    return ia;
  }

  static boost::archive::xml_oarchive&
  stream(boost::archive::xml_oarchive& oa,
         const boost::serialization::nvp<double>& nvp)
  {
    if(std::isnan(nvp.value())) {
      std::string nanStr = nanCStr;
      oa << boost::serialization::make_nvp(nvp.name(), nanStr);
    }
    else {
      std::stringstream oStrm;
      oStrm << std::setprecision(std::numeric_limits<double>::digits10 + 1)
            << nvp.value();
      std::string oStr = oStrm.str();
      oa << boost::serialization::make_nvp(nvp.name(), oStr);
    }
    return oa;
  }
};
boost/archive/basic_text_iprimitive.hpp

template< class IStream >
class basic_text_iprimitive
 template<class T>
 void load(T & t)
namespace boost { namespace archive {
template<> template<>
void basic_text_iprimitive< std::istream >::load<double>( double& t )
{
    // fix to handle NaNs
}
} } // close namespaces
std::locale infLocale( std::locale(), new boost::math::nonfinite_num_get<char>));
is.imbue( infLocale )