Ошибка компиляции при использовании расширенной сериализации для контейнеров stl с не копируемыми значениями

Если у меня есть не копируемый класс и я использую этот класс в качестве типа значения контейнера stl, который я хотел сериализовать с помощью boost serialize, я получаю ошибку компиляции, которая указывает, что я хотел использовать удаленную функцию. Простой код, который вызывает ошибку, выглядит так:

#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,

Есть ли у меня ошибка при использовании boost или это неправильное поведение сериализации boost?

Я использовал C++11 с g++-4.8, и моя буст-версия 1-60.0 скомпилирована из исходного кода.

Редактировать:

Как сказал @sehe в своем ответе, используя g++-5.x, можно решить ошибку компиляции. Но это верно только для std::vector и используя другие контейнеры, такие как std::unordered_map вызывает ту же ошибку компиляции даже с g++-5.x.

2 ответа

Решение

Кажется, ошибка в буст-коде, я сообщил об этом в баг-трекере. Но для быстрого решения вы можете изменить одну строку в файле 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.

Проблемы, кажется, в том, что std::string не является noexcept двигаться переуступке:

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

(это из строки 584 в моем basic_string.h)

Действительно замена std::string с int заставить все работать нормально

Жить на Колиру

#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;
    }
}
Другие вопросы по тегам