对具有不可复制值的 stl 容器使用升压序列化时出现编译错误
Compilation error in using boost serialization for stl containers with non-copyable values
如果我有一个不可复制的 class 并使用这个 class 作为我想使用 boost serialize 序列化它的 stl 容器的值类型,我得到一个编译错误,表明我曾想使用已删除的功能。导致错误的简单代码是这样的:
#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 serialize 的错误行为?
我在 g++-4.8 中使用了 c++11,我的 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 行)
确实将 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;
}
}
这似乎是 boost 代码中的错误,我在 boost 错误跟踪器中报告了 this。但是对于快速解决方案,您可以更改文件中的一行 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 插入。可能是通用的解决方案,但目前这个补丁解决了我的问题。
更新:
正如 bug 所报告的那样,此错误已在 boost-1.61 中修复。
如果我有一个不可复制的 class 并使用这个 class 作为我想使用 boost serialize 序列化它的 stl 容器的值类型,我得到一个编译错误,表明我曾想使用已删除的功能。导致错误的简单代码是这样的:
#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 serialize 的错误行为?
我在 g++-4.8 中使用了 c++11,我的 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 行)
确实将 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;
}
}
这似乎是 boost 代码中的错误,我在 boost 错误跟踪器中报告了 this。但是对于快速解决方案,您可以更改文件中的一行 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 插入。可能是通用的解决方案,但目前这个补丁解决了我的问题。
更新:
正如 bug 所报告的那样,此错误已在 boost-1.61 中修复。