24

のシリアル化用のBoostモジュールがあることは知っていますが、の何も見つかりません。boost::shared_ptrstd::shared_ptr

また、簡単に実装する方法もわかりません。次のコードが怖いです

namespace boost{namespace serialization{
template<class Archive, class T>
inline void serialize(Archive & ar, std::shared_ptr<T> &t, const unsigned int version)
{
  if(Archive::is_loading::value) {T*r;ar>>r;t=r;}
  else {ar<<t.get();}
}
}}//namespaces

動作しません。実際、あるオブジェクトが複数回参照された場合、そのオブジェクトはの最初の実行でロードされar>>r、その後はポインタだけがコピーされます。ただしshared_ptr、それを指す複数のオブジェクトを作成するため、複数回破壊します。

それについて何かアイデアはありますか?

私が使用しているシステムに関するいくつかの技術的な詳細:

  • OS:Ubuntu 11.10(x64)
  • コンパイラ:g ++(Ubuntu / Linaro 4.6.1-9ubuntu3)4.6.1
  • ブーストバージョン:1.46.1(でインストールsudo apt-get install libboost-dev
4

7 に答える 7

15

私はついに、ブーストシリアル化を使用してstd::shared_ptrをシリアル化する方法に関する解決策を見つけました。必要なのは次のコードです(説明は次のとおりです)。

#include <boost/serialization/split_free.hpp>
#include <boost/unordered_map.hpp>

//---/ Wrapper for std::shared_ptr<> /------------------------------------------

namespace boost { namespace serialization {

template<class Archive, class Type>
void save(Archive & archive, const std::shared_ptr<Type> & value, const unsigned int /*version*/)
{
    Type *data = value.get();
    archive << data;
}

template<class Archive, class Type>
void load(Archive & archive, std::shared_ptr<Type> & value, const unsigned int /*version*/)
{
    Type *data;
    archive >> data;

    typedef std::weak_ptr<Type> WeakPtr;
    static boost::unordered_map<void*, WeakPtr> hash;

    if (hash[data].expired())
    {
         value = std::shared_ptr<Type>(data);
         hash[data] = value;
    }
    else value = hash[data].lock();
}

template<class Archive, class Type>
inline void serialize(Archive & archive, std::shared_ptr<Type> & value, const unsigned int version)
{
    split_free(archive, value, version);
}

}}

このコードは、関数save()のstd::shared_ptrによって管理されるオブジェクトを単にシリアル化します。複数のstd::shared_ptrインスタンスが同じオブジェクトを指している場合、ブーストシリアル化は自動的にそれを1回だけ保存するように注意します。魔法はload()で発生し、ブーストシリアル化はオブジェクト(データ)への生のポインターを返します。この生のポインターは、各生のポインターのweak_ptrを保持するハッシュで検索されます。ハッシュ内のweak_ptrの有効期限が切れた場合、新しいshared_ptrインスタンスを安全に作成し、rawポインターを管理させ、weak_ptrをハッシュに格納できます。weak_ptrの有効期限が切れていない場合は、単にロックしてshared_ptrを返します。このようにして、参照カウントは正しくなります。

于 2013-02-21T10:04:27.883 に答える
15

Boost 1.56の時点で、シリアル化ライブラリにはstd::shared_ptrのサポートが組み込まれています。ライブラリの最新バージョンを使用できる場合は、独自のシリアル化ヘルパー関数を実装する必要はありません。

于 2015-01-17T20:02:00.547 に答える
3

シリアル化は、標準ライブラリではなくブーストによって提供され、標準shared_ptrに含まれていますが、TR1の一部です(テクニカルレポート1)。

現在のところ、TR1にはシリアル化がありません。したがって、boostの共有ポインタを使用することをお勧めします。

于 2012-02-17T10:18:38.880 に答える
2

「機能しない」とはどういう意味か、あなたは言っていません。コンパイルされませんか?値が正しくロード/保存されませんか?それは..何ですか?

ここで特定できる問題は2つありますが、1つは意図的な設計の一部である可能性があります。

まず、ロード手順で正しいポインタを作成していません。それを分解しましょう:

inline void serialize(Archive & ar, std::shared_ptr<T> &t, const unsigned int version) {
    if (1) { //unimportant
        T* r;
        ar >> r;
        t = r;
    }
}

std :: shared_ptrのオブジェクトを作成すると、クラステンプレートをインスタンス化して、ポインターのような機能を提供します(ご存知のとおり)。intで作成した場合は、intポインタとして機能します。ただし、タイプをTとして渡すだけでは、そのタイプで作成されたポインターが自動的にそのテンプレートを使用するわけではありません。実際、T*rを使用してベアポインタを作成しています。int*rの場合もあります。次に、newで初期化できません。rはどこを指している可能性があります。newで適切に初期化された場合、そのオブジェクトの作成/削除に対して正しい参照カウントを取得できます。これは、std::shared_ptrが私にとって努力する価値がないと思われる領域の1つです。ベアポインタからの割り当ては、最初の参照ではなく2番目の参照としてカウントされると思いますが、間違っている可能性がありますか?とにかく、それは問題ではありません。おそらくヒープが破損しています。コンパイラは、初期化されていないポインタの使用について警告を発する必要がありますが、そうではないのは不思議です。警告がオフになっていないことを願っています。

私の記憶が正しければ、rの宣言を次のように置き換える必要があります。

std::shared_ptr<T> r = new std::shared_ptr<T>;

かもしれませんが

std::shared_ptr<T> r = new std::shared_ptr<T>(r());

しばらくshared_ptrを使用していません。

ちなみに、TR1は少なくとも2年前から出ています。これは、boostのshared_ptrに基づいています。Boost 1.46を使用している理由はわかりませんが、shared_ptrが標準の一部になるまでには使用されていなかったと思いますか?互換性があるはずです...?

とにかく、2番目の潜在的なエラーは

t = r;

私は仮定しています-間違っていますか?-参照カウントを再割り当てして(場合によってはtが指すオブジェクトを破棄して)tにデクリメントしたいこと。あなたがそれをコピーするつもりなら、あなたはもちろん以下を使うでしょう:

*t = *r;

コピーコンストラクタが正しく機能することを確認してください。

于 2012-01-12T15:50:54.607 に答える
2

Boost Serializationの最近のバージョンには、すべての標準ライブラリスマートポインタのサポートが含まれています。

于 2015-11-24T23:01:10.823 に答える
0

これは、同じメモリを指すが異なるタイプのshared_ptrのロードをサポートするデニムのソリューションの改善です。この問題は、AがBから継承されている同じオブジェクトを指しているshared_ptrとshared_ptrがアーカイブに同時に含まれている場合に発生する可能性があります。

namespace boost {
namespace serialization {

    template<class Archive, class Type>
    void save(Archive & archive, const std::shared_ptr<Type> & value, const unsigned int /*version*/)
    {
        Type *data = value.get();
        archive << data;
    }

    static std::map<void*, std::weak_ptr<void>> hash;

    template<class Archive, class Type>
    void load(Archive & archive, std::shared_ptr<Type> & value, const unsigned int /*version*/)
    {
        Type *data;
        archive >> data;

        if (hash[data].expired())
        {
            std::shared_ptr<void> ptr(data);
            value = static_pointer_cast<Type>(ptr);
            hash[data] = ptr;
        }
        else value = static_pointer_cast<Type>(hash[data].lock());
    }

    template<class Archive, class Type>
    inline void serialize(Archive & archive, std::shared_ptr<Type> & value, const unsigned int version)
    {
        split_free(archive, value, version);
    }

}}

この認識の弱点として-1つの巨大な地図。

于 2014-12-25T22:53:22.693 に答える
0

これは、たとえばに基づいて、ブースト共有ポインタヘッダーに基づいて独自にローリングした結果です<boost/serialization/shared_ptr.hpp>

以下をコピーしてヘッダーファイルに貼り付け、インクルードするだけです。

#ifndef BOOST_SERIALIZATION_STD_SHARED_PTR_HPP
#define BOOST_SERIALIZATION_STD_SHARED_PTR_HPP

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// shared_ptr.hpp: serialization for boost shared pointer

// (C) Copyright 2004 Robert Ramey and Martin Ecker
// Use, modification and distribution is subject to 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)

//  See http://www.boost.org for updates, documentation, and revision history.

#include <cstddef> // NULL

#include <boost/config.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/integral_c_tag.hpp>

#include <boost/detail/workaround.hpp>
#include <memory>

#include <boost/serialization/split_free.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/tracking.hpp>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// shared_ptr serialization traits
// version 1 to distinguish from boost 1.32 version. Note: we can only do this
// for a template when the compiler supports partial template specialization

#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
    namespace boost {
    namespace serialization{
        template<class T>
        struct version< ::std::shared_ptr< T > > {
            typedef mpl::integral_c_tag tag;
            #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206))
            typedef BOOST_DEDUCED_TYPENAME mpl::int_<1> type;
            #else
            typedef mpl::int_<1> type;
            #endif
            #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570))
            BOOST_STATIC_CONSTANT(int, value = 1);
            #else
            BOOST_STATIC_CONSTANT(int, value = type::value);
            #endif
        };
        // don't track shared pointers
        template<class T>
        struct tracking_level< ::std::shared_ptr< T > > {
            typedef mpl::integral_c_tag tag;
            #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206))
            typedef BOOST_DEDUCED_TYPENAME mpl::int_< ::boost::serialization::track_never> type;
            #else
            typedef mpl::int_< ::boost::serialization::track_never> type;
            #endif
            #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570))
            BOOST_STATIC_CONSTANT(int, value = ::boost::serialization::track_never);
            #else
            BOOST_STATIC_CONSTANT(int, value = type::value);
            #endif
        };
    }}
    #define BOOST_SERIALIZATION_SHARED_PTR(T)
#else
    // define macro to let users of these compilers do this
    #define BOOST_SERIALIZATION_SHARED_PTR(T)                         \
    BOOST_CLASS_VERSION(                                              \
        ::std::shared_ptr< T >,                                     \
        1                                                             \
    )                                                                 \
    BOOST_CLASS_TRACKING(                                             \
        ::std::shared_ptr< T >,                                     \
        ::boost::serialization::track_never                           \
    )                                                                 \
    /**/
#endif

namespace boost {
namespace serialization{

#ifndef BOOST_SERIALIZATION_SHARED_PTR_HPP
struct null_deleter {
    void operator()(void const *) const {}
};
#endif

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// serialization for shared_ptr

template<class Archive, class T>
inline void save(
    Archive & ar,
    const std::shared_ptr< T > &t,
    const unsigned int /* file_version */
){
    // The most common cause of trapping here would be serializing
    // something like shared_ptr<int>.  This occurs because int
    // is never tracked by default.  Wrap int in a trackable type
    BOOST_STATIC_ASSERT((tracking_level< T >::value != track_never));
    const T * t_ptr = t.get();
    ar << boost::serialization::make_nvp("px", t_ptr);
}

template<class Archive, class T>
inline void load(
    Archive & ar,
    std::shared_ptr< T > &t,
    const unsigned int /*file_version*/
){
    // The most common cause of trapping here would be serializing
    // something like shared_ptr<int>.  This occurs because int
    // is never tracked by default.  Wrap int in a trackable type
    BOOST_STATIC_ASSERT((tracking_level< T >::value != track_never));
    T* r;
    ar >> boost::serialization::make_nvp("px", r);
    ar.reset(t,r);
}

template<class Archive, class T>
inline void serialize(
    Archive & ar,
    std::shared_ptr< T > &t,
    const unsigned int file_version
){
    // correct shared_ptr serialization depends upon object tracking
    // being used.
    BOOST_STATIC_ASSERT(
        boost::serialization::tracking_level< T >::value
        != boost::serialization::track_never
    );
    boost::serialization::split_free(ar, t, file_version);
}

} // namespace serialization
} // namespace boost

#endif // BOOST_SERIALIZATION_STD_SHARED_PTR_HPP

ここまでの違いを見ることができます<boost/serialization/shared_ptr.hpp>

基本的に、

  • インクルードガードに名前が変更されました
  • に変更されboost::shared_ptrましたstd::shared_ptr
  • <memory>の代わりに含まれています<boost/shared_ptr.hpp>
  • null_deleter使用する場合に備えて、再定義から保護されていますboost::shared_ptr
  • 削除されBOOST_SERIALIZATION_SHARED_PTR_132_HPPました-それは何ですか?

これまでのところ、これは問題なく機能しているようです。

于 2015-02-18T14:26:57.560 に答える