如何知道 shared_ptr 是否已经序列化以提升存档
How to know if shared_ptr was already serialized to boost archive
在我的程序中,我有 c++ class 对象保留 SmartPointers 成员(SmartPointer 是我自己的自定义 class 派生自 boost::shared_ptr)。按照设计,我的某些 class 对象必须保留唯一的 SmartPtr,即不允许共享所有权。
出于调试的原因,我想实现检查模块,它将测试给定的 c++ class 对象(c++ 对象本身可以包含嵌套的 c++ class 对象成员)是否保持共享的智能指针所有权。如果是,我想抛出异常。我正在考虑为此目的重用序列化库,因为我已经为所有 classes 提供了序列化函数。我所要做的就是在我的 SmartPointer::serialize 函数中添加检查代码来测试指针是否已经保存在存档中。所以任何人都知道 boost 序列化中的这种功能会告诉我指针对象是否已经序列化?我认为 boost 序列化库必须有机制来检查这一点,因为在存档输出中,共享所有权的 shared_ptrs 只写了一次。
代码味道正在使用 shared_ptr,其中必须保证唯一所有权。发现违规后怎么办?断言? std::terminate
?
您可以制作一个序列化包装器,添加对反序列化的检查。
您将取决于库的实现细节,因为 - 显然 - 在加载时会有 shared_ptr:
的临时副本
#undef NDEBUG
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/wrapper.hpp>
#include <iostream>
template <typename SP> struct Unique {
SP& _ref;
Unique(SP& r):_ref(r){}
template <typename Ar>
void serialize(Ar& ar, unsigned) {
if constexpr (typename Ar::is_saving{}) {
if (_ref && not _ref.unique())
throw std::logic_error("Shared ownership not allowed");
}
ar & _ref;
if constexpr (typename Ar::is_loading{}) {
if (_ref && _ref.use_count() != 2)
throw std::logic_error("Shared ownership not allowed");
}
}
};
template <typename SP>
struct boost::serialization::is_wrapper<Unique<SP>> : boost::mpl::true_ {};
struct Data {
int a,b,c;
void serialize(auto& ar, unsigned) { ar & a & b & c; }
};
static std::string do_write(auto const&... data) {
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
(oa << ... << data);
return oss.str();
}
static void do_read(std::string const& str, auto&&... data)
{
std::istringstream iss(str);
boost::archive::text_iarchive ia(iss);
(ia >> ... >> data);
}
int main()
{
auto data = std::make_shared<Data>(1, 2, 3);
assert(data.unique());
// okay:
{
auto txt = do_write(data, data, data);
do_read(txt, data);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
}
// still okay:
{
Unique ud{data};
auto txt = do_write(ud);
do_read(txt, ud);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
assert(data.unique());
}
// not okay because not unique:
try
{
auto data_shared(data);
Unique ud{data}, ud_shared{data_shared};
assert(!data.unique());
assert(!data_shared.unique());
auto txt = do_write(ud, ud_shared);
do_read(txt, ud, ud_shared);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
}catch(std::exception const& e) {
std::cout << "L:" << __LINE__ << " Failure " << e.what() << std::endl;
}
}
版画
L:57 Success
L:65 Success
L:81 Failure Shared ownership not allowed
总结
不要这样做,因为你不能干净地做到这一点。另一种选择更糟糕(如一些评论者所建议的那样深入研究对象跟踪实现细节)。
简单
- 收紧类型约束以表达您的不变性
- 也许添加一个验证成员来检查不变量
在我的程序中,我有 c++ class 对象保留 SmartPointers 成员(SmartPointer 是我自己的自定义 class 派生自 boost::shared_ptr)。按照设计,我的某些 class 对象必须保留唯一的 SmartPtr,即不允许共享所有权。
出于调试的原因,我想实现检查模块,它将测试给定的 c++ class 对象(c++ 对象本身可以包含嵌套的 c++ class 对象成员)是否保持共享的智能指针所有权。如果是,我想抛出异常。我正在考虑为此目的重用序列化库,因为我已经为所有 classes 提供了序列化函数。我所要做的就是在我的 SmartPointer::serialize 函数中添加检查代码来测试指针是否已经保存在存档中。所以任何人都知道 boost 序列化中的这种功能会告诉我指针对象是否已经序列化?我认为 boost 序列化库必须有机制来检查这一点,因为在存档输出中,共享所有权的 shared_ptrs 只写了一次。
代码味道正在使用 shared_ptr,其中必须保证唯一所有权。发现违规后怎么办?断言? std::terminate
?
您可以制作一个序列化包装器,添加对反序列化的检查。
您将取决于库的实现细节,因为 - 显然 - 在加载时会有 shared_ptr:
的临时副本#undef NDEBUG
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/wrapper.hpp>
#include <iostream>
template <typename SP> struct Unique {
SP& _ref;
Unique(SP& r):_ref(r){}
template <typename Ar>
void serialize(Ar& ar, unsigned) {
if constexpr (typename Ar::is_saving{}) {
if (_ref && not _ref.unique())
throw std::logic_error("Shared ownership not allowed");
}
ar & _ref;
if constexpr (typename Ar::is_loading{}) {
if (_ref && _ref.use_count() != 2)
throw std::logic_error("Shared ownership not allowed");
}
}
};
template <typename SP>
struct boost::serialization::is_wrapper<Unique<SP>> : boost::mpl::true_ {};
struct Data {
int a,b,c;
void serialize(auto& ar, unsigned) { ar & a & b & c; }
};
static std::string do_write(auto const&... data) {
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
(oa << ... << data);
return oss.str();
}
static void do_read(std::string const& str, auto&&... data)
{
std::istringstream iss(str);
boost::archive::text_iarchive ia(iss);
(ia >> ... >> data);
}
int main()
{
auto data = std::make_shared<Data>(1, 2, 3);
assert(data.unique());
// okay:
{
auto txt = do_write(data, data, data);
do_read(txt, data);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
}
// still okay:
{
Unique ud{data};
auto txt = do_write(ud);
do_read(txt, ud);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
assert(data.unique());
}
// not okay because not unique:
try
{
auto data_shared(data);
Unique ud{data}, ud_shared{data_shared};
assert(!data.unique());
assert(!data_shared.unique());
auto txt = do_write(ud, ud_shared);
do_read(txt, ud, ud_shared);
std::cout << "L:" << __LINE__ << " Success " << std::endl;
}catch(std::exception const& e) {
std::cout << "L:" << __LINE__ << " Failure " << e.what() << std::endl;
}
}
版画
L:57 Success
L:65 Success
L:81 Failure Shared ownership not allowed
总结
不要这样做,因为你不能干净地做到这一点。另一种选择更糟糕(如一些评论者所建议的那样深入研究对象跟踪实现细节)。
简单
- 收紧类型约束以表达您的不变性
- 也许添加一个验证成员来检查不变量