mirror of
https://github.com/boostorg/serialization.git
synced 2026-07-21 13:33:32 +00:00
Move, don't copy, the loaded value into the optional
`load_impl` read the value into a local and copy-assigned it to the optional. A move-only type then failed to compile: `optional`'s perfect-forwarding assignment is removed by SFINAE when the value is not copy-assignable, leaving no viable `operator=`. So, move the local into the optional instead. The one-line fix was proposed by Venkat Murty in PR #330; this extends it with `boost::move` and a regression test.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/serialization/item_version_type.hpp>
|
||||
#include <boost/serialization/library_version_type.hpp>
|
||||
#include <boost/serialization/version.hpp>
|
||||
@@ -83,7 +84,7 @@ void load_impl(
|
||||
}
|
||||
typename OT::value_type t;
|
||||
ar >> boost::serialization::make_nvp("value",t);
|
||||
ot = t;
|
||||
ot = boost::move(t);
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// test_optional.cpp
|
||||
|
||||
// (C) Copyright 2004 Pavel Vozenilek
|
||||
// Copyright 2026 Gennaro Prota
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -92,6 +93,59 @@ int test(){
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// A move-only value type: deleted copy, defaulted move. Loading an
|
||||
// optional<M> must move the deserialized value into place rather than copy
|
||||
// it.
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) \
|
||||
&& !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) \
|
||||
&& !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS)
|
||||
#define BOOST_SERIALIZATION_TEST_OPTIONAL_MOVE_ONLY
|
||||
|
||||
struct M {
|
||||
int m_x;
|
||||
M() : m_x(0) {}
|
||||
explicit M(int x) : m_x(x) {}
|
||||
M(const M &) = delete;
|
||||
M & operator=(const M &) = delete;
|
||||
M(M &&) = default;
|
||||
M & operator=(M &&) = default;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int /* version */){
|
||||
ar & boost::serialization::make_nvp("x", m_x);
|
||||
}
|
||||
};
|
||||
|
||||
template<template<class> class Optional>
|
||||
int test_move_only(){
|
||||
const char * testfile = boost::archive::tmpnam(NULL);
|
||||
BOOST_REQUIRE(NULL != testfile);
|
||||
|
||||
Optional<M> o_empty;
|
||||
Optional<M> o_value(M(42));
|
||||
{
|
||||
test_ostream os(testfile, TEST_STREAM_FLAGS);
|
||||
test_oarchive oa(os, TEST_ARCHIVE_FLAGS);
|
||||
oa << boost::serialization::make_nvp("o_empty", o_empty);
|
||||
oa << boost::serialization::make_nvp("o_value", o_value);
|
||||
}
|
||||
// start each target in the opposite state, so load must both reset and
|
||||
// assign
|
||||
Optional<M> o_empty_a(M(7));
|
||||
Optional<M> o_value_a;
|
||||
{
|
||||
test_istream is(testfile, TEST_STREAM_FLAGS);
|
||||
test_iarchive ia(is, TEST_ARCHIVE_FLAGS);
|
||||
ia >> boost::serialization::make_nvp("o_empty", o_empty_a);
|
||||
ia >> boost::serialization::make_nvp("o_value", o_value_a);
|
||||
}
|
||||
BOOST_CHECK(! o_empty_a);
|
||||
BOOST_CHECK(static_cast<bool>(o_value_a) && 42 == o_value_a->m_x);
|
||||
|
||||
std::remove(testfile);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif // move-only support available
|
||||
|
||||
#include <boost/serialization/optional.hpp>
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
#include <optional>
|
||||
@@ -102,5 +156,11 @@ int test_main( int /* argc */, char* /* argv */[] ){
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
test<std::optional>();
|
||||
#endif
|
||||
#ifdef BOOST_SERIALIZATION_TEST_OPTIONAL_MOVE_ONLY
|
||||
test_move_only<boost::optional>();
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
test_move_only<std::optional>();
|
||||
#endif
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user