对具有不可复制值的 stl 容器使用提升序列化时出现编译错误



如果我有一个不可复制的类并将该类用作 stl 容器的值类型,我想使用 boost 序列化对其进行序列化,我会收到一个编译错误,表明我想使用已删除的函数。导致错误的简单代码如下所示:

#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/string.hpp>
#include <fstream>
#include <iostream>
#include <unordered_map>
using namespace std;
class Foo
{                                                                                                                                                                                
public:
  string s;
  Foo()
  {}
  Foo(string s):
    s(s)
  {}

  Foo(const Foo& other) = delete;
  Foo &operator=(const Foo &other) = delete;
  Foo(Foo &&other) noexcept = default;
  Foo &operator=(Foo &&other) noexcept = default;

  template <typename Archive>
  void save(Archive &ar, const unsigned int version) const
  {
    ar & this->s;
  }
  template <typename Archive>
  void load(Archive &ar, const unsigned int version)
  {
    ar & this->s;
  }
  BOOST_SERIALIZATION_SPLIT_MEMBER()
  friend class boost::serialization::access;
};
int main(int argc, char *argv[])
{
  vector<pair<const uint8_t, Foo>> bar;
  const char* text_file_name = "/tmp/test-fixed-multibit.txt";
  {
    std::ofstream ofs(text_file_name);
    boost::archive::text_oarchive ar(ofs);
    ar & bar;
  }
  {
    vector<pair<const uint8_t, Foo>> bar1;
    std::ifstream ifs(text_file_name);
    boost::archive::text_iarchive ar(ifs);
    ar & bar1;
  }
  return 0;
}

它给了我这样的错误:

/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const unsigned char; _T2 = Foo]’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^
In file included from /usr/include/c++/4.8/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/4.8/vector:60,
                 from /usr/local/include/boost/serialization/vector.hpp:20,
                 from foo.cc:3:
/usr/include/c++/4.8/bits/stl_pair.h:128:17: note: ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const unsigned char; _T2 = Foo]’ is implicitly deleted because the default definition would be ill-formed:
       constexpr pair(pair&&) = default;
                 ^
/usr/include/c++/4.8/bits/stl_pair.h:128:17: error: use of deleted function ‘Foo::Foo(const Foo&)’
foo.cc:28:3: error: declared here
   Foo(const Foo& other) = delete;

我删除了错误的某些部分,但它们就像我们在这里复制的行。您可以通过将Foo替换为另一种类型(如 string )来检查代码的正确性。

我在使用提升时是否有错误,或者这是提升序列化的不当行为?

我将 c++11 与 g++-4.8 一起使用,我的 boost 版本是从源代码编译的 1-60.0。

编辑:

正如@sehe在他的回答中所述,使用 g++-5.x 可以解决编译错误。但这仅适用于std::vector,使用其他容器(如std::unordered_map即使使用 g++-5.x也会导致相同的编译错误。

问题似乎是std::string不是noexcept可移动分配的:

  // PR 58265, this should be noexcept.
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 2063. Contradictory requirements for string move assignment

(这是我basic_string.h中的第584行)

事实上,用

int替换std::string可以使一切正常:

住在科里鲁

#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/string.hpp>
#include <fstream>
#include <iostream>
#include <unordered_map>
struct Foo {
    int s;
    Foo(int s = {}) : s(s) {}
    Foo(const Foo &other) = delete;
    Foo &operator=(const Foo &other) = delete;
    Foo(Foo &&other) noexcept = default;
    Foo &operator=(Foo &&other) noexcept = default;
    template <typename Archive> void save(Archive &ar, const unsigned int version) const { ar & this->s; }
    template <typename Archive> void load(Archive &ar, const unsigned int version) { ar & this->s; }
    BOOST_SERIALIZATION_SPLIT_MEMBER()
    friend class boost::serialization::access;
};
int main(int argc, char *argv[]) {
    std::vector<std::pair<const uint8_t, Foo> > bar;
    const char *text_file_name = "test-fixed-multibit.txt";
    {
        std::ofstream ofs(text_file_name);
        boost::archive::text_oarchive ar(ofs);
        ar & bar;
    }
    {
        std::vector<std::pair<const uint8_t, Foo> > bar1;
        std::ifstream ifs(text_file_name);
        boost::archive::text_iarchive ar(ifs);
        ar & bar1;
    }
}

这似乎是提升代码中的一个错误,我在提升错误跟踪器中报告了这个错误。但是对于快速解决方案,您可以更改文件中的一行boost/serialization/archive_input_unordered_map.hpp第 43 行 ( s.insert(t.reference()); ) 必须替换为:

  s.emplace(std::piecewise_construct,
            std::forward_as_tuple(std::move(t.reference().first)),
            std::forward_as_tuple(std::move(t.reference().second)));

这是针对 boost-1.60 的,您必须在其他版本中找到该行,它只是纠正unordered_map插入。可能是通用解决方案,但目前此补丁解决了我的问题。

更新:

正如所报告的错误一样,此错误已在 boost-1.61 中修复。

最新更新