$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [Boost-users] [serialization] Memory leaks even with shared_ptrs
From: cc caprani (cc.caprani_at_[hidden])
Date: 2011-07-21 16:55:02
On Thu, Jul 21, 2011 at 8:32 PM, cc caprani <cc.caprani_at_[hidden]> wrote:
>
> This very simple program still leaks one copy of everything loaded from the
> archive.
>
>
I've done some more on this and the leak only occurs if a virtual member
function is declared in the base class. It doesn't matter if the function is
pure virtual or concrete, and whether or not
BOOST_SERIALIZATION_ASSUME_ABSTRACT is used. Turning off both virtual base
class member functions removes the leak.
At this stage I think it must be a bug - should I form a tracker for it? Or
am I not understanding something?
Here is a minimal program to replicate the leak (using VS2010, boost 1.47).
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <fstream>
#include <crtdbg.h>
class Distribution
{
public:
    Distribution(void) {};
    ~Distribution(void) {};
    // turn on either to get memory leak
    virtual int getType() = 0;
    //virtual int getType() {return 1;};
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int version) {};
};
typedef boost::shared_ptr<Distribution> DistributionPtr;
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Distribution)
class ContinuousDist :    public Distribution
{
public:
    ContinuousDist(){};
    ~ContinuousDist(void) {};
    virtual int getType() {return 1;};
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int version)
    { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Distribution); };
};
BOOST_CLASS_EXPORT(ContinuousDist);
class DiscreteDist : public Distribution
{
public:
    DiscreteDist(void)
    {
        m_Data.push_back(4.0);
        m_Data.push_back(8.0);
    };
    ~DiscreteDist(void){};
    virtual int getType() {return 2;};
private:
    std::vector<double> m_Data;
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int version)
    {
        ar    & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Distribution)
            & BOOST_SERIALIZATION_NVP(m_Data);
    };
};
BOOST_CLASS_EXPORT(DiscreteDist);
class Parameter
{
public:
    Parameter(){};
    Parameter(int type)
    {
        if(type == 1)
            m_pDist = boost::make_shared<DiscreteDist>();
        else
            m_pDist = boost::make_shared<ContinuousDist>();
    };
    ~Parameter(void){};
private:
    DistributionPtr m_pDist;
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& ar, const unsigned int version)
    { ar & BOOST_SERIALIZATION_NVP(m_pDist); };
};
typedef boost::shared_ptr<Parameter> ParameterPtr;
void load(std::vector<ParameterPtr>& vP, std::string file)
{
    std::ifstream ifs(file.c_str());
    boost::archive::xml_iarchive ia(ifs);
    ia >> BOOST_SERIALIZATION_NVP(vP);
}
void save(std::vector<ParameterPtr>& vP, std::string file)
{
    std::ofstream ofs(file.c_str());
    boost::archive::xml_oarchive oa(ofs);
    oa << BOOST_SERIALIZATION_NVP(vP);
}
int main()
{
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    // the file to read/save from/to
    std::string file = "archive.xml";
    // make some Parmeters
    std::vector<ParameterPtr> vParam;
    vParam.push_back( boost::make_shared<Parameter>(1) );
    vParam.push_back( boost::make_shared<Parameter>(2) );
    // save the file
    std::cout << "Writing..." << std::endl;
    save(vParam,file);
    // clear it
    vParam.clear();
    // read the file
    std::cout << "Reading..." << std::endl;
    load(vParam,file);
    return 0;
}