1

I don't have access to the Boost library and am trying to implement something similar to Boost any (a container that can store multiple types). I found an example at http://learningcppisfun.blogspot.co.uk/2007/09/boostany.html, however when I compile it I get a segmentation fault. Debugging it seems to suggest that it's Variant's destructor causing an issue. When I comment the destructor out it works fine -- although it's leaking memory. Can anyone explain what's happening? Thanks!

#include <iostream>
#include <vector>

using namespace std;

class BaseHolder
{
    public:
        virtual ~BaseHolder(){}
};

template<typename T>
class HoldData : public BaseHolder
{
    public:
        HoldData(const T& t_) : t(t_){}
        T t;
};

class Variant
{
public:
    template<typename T>
    Variant(const T& t) : data(new HoldData<T>(t)){}
    ~Variant(){delete data;}
    BaseHolder* data;
};

int main(){
    vector<Variant> a;
    int x = 10;
    double y = 3.15;
    a.push_back(x);
    a.push_back(y);

    cout << dynamic_cast<HoldData<int> *>(a[0].data)->t << endl;
    cout << dynamic_cast<HoldData<double> *>(a[1].data)->t << endl;

    return 0;
}

Output:

10
3.5 
clcto
  • 9,530
  • 20
  • 42

2 Answers2

2

You have a basic violation of the rule of three.

You allocate in the default constructor, and de-allocate in the destructor. Now, what about your copy constructor and assignment operator? What about when two Variant objects point to the same data, and then they both go out of scope?

Since vectors maintain internal integrity by copying elements around and, in fact hold copies in the first place, it should be clear that this is a serious factor.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I was under the impression that the variables that data ultimately points to (whatever is in t) were copy constructed, and so didn't think it was possible for the two Variant objects to point to the same data. Maybe this is not the case? – user3685366 Jul 31 '14 at 22:20
  • @user3685366: No that is not the case. Your member variable is not `t`, it is `data`. `data` is a pointer, and that pointer will of course be copied. But both copies will point to the same thing. Indeed this is rather the entire purpose of pointers! – Lightness Races in Orbit Jul 31 '14 at 23:05
1

What I think is happening is this

  1. You push int 10 onto the vector a

  2. This triggers Constructor call for a temp Variant lets call this var1.

  3. Constructor calls new HoldData (10)

  4. Now vector a calls the Variant's copy constructor (which is automatically supplied by compiler) to create a Variant var2 in the vector. The default copy constructor is just a bitwise copy so var1 and var2 both have a data pointer pointing to same place.

  5. var1 now goes out of scope and its destructor is called deleting its data pointer.

  6. var2 in the vector now has a pointer to invalid memory. When vector a goes out of scope var2 will call its destructor and try to delete the memory a second time hence the crash.

You need to provide your own copy constructor in Variant that will safely copy the HoldData pointer.

David Woo
  • 749
  • 4
  • 13