0

I was trying my own implementation of a generic container of arbitrary type (similar to boost:any) just to learn about the idiom, and I am trying to understand why my code gives a segmentation fault.

class IValue
{
public:
    IValue() = default;
    virtual ~IValue() = default;
};

template<typename T>
class Value : public IValue
{
public:
    Value(T value) : val(value){}

    virtual ~Value() override
    {
    }

    T get()
    {
        return val;
    }
private:
    T val;
};

class any
{

public:
    template<typename U>
    any(U element)
    {
        elem = new Value<U>(element);
    }

    ~any()
    {
        delete elem;
    }

    IValue* get_type_erased_value()
    {
        return elem;
    }


private:
    IValue* elem;
};

template<typename T>
T any_cast(any a)
{
    Value<T>* stored_element = dynamic_cast<Value<T>*>(a.get_type_erased_value());

    if(stored_element)
    {
        return stored_element->get();
    }
    else
    {
        cout << "Any cast failed. Could not cast down to required type\n";
        return T();
    }

}

struct foo
{
    int a;
    float b;
    char c;
};

ostream& operator<<(ostream& stream, foo& a)
{
    stream << '{' << a.a << ',' << a.b << ',' << a.c << '}' << '\n';
    return stream;
}

int main()
{
    any a = string("Any string value");

    any b = int(17);

    any c = foo({27,3.5,'g'});

    string s = any_cast<string>(a);
    int i = any_cast<int>(b);
    foo f = any_cast<foo>(c);

    cout << "Any string contained: " << s << '\n';
    cout << "Any int contained: " << i << '\n';
    cout << "Any struct foo contained: " << f << '\n';

    return 0;
}

The output is what I desire and the casts seem to work correctly, but the program always crashes at the end. There must be something wrong with the destructor not being called correctly or the deallocation of the pointer. Can someone give me a hint?

Thanks

bone
  • 144
  • 2
  • 6
  • Have you tried debugging? – erenon Nov 06 '17 at 22:34
  • [UBsan](http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) says "runtime error: member call on address 0x6030000000a0 which does not point to an object of type 'IValue' 0x6030000000a0: note: object has invalid vptr" in line `delete elem;` whereas [Asan](http://clang.llvm.org/docs/AddressSanitizer.html) says "heap-use-after-free" in the same line, memory deleted in the line `foo f = any_cast(c);` and again in the destructor at the end of `main`. – nwp Nov 06 '17 at 22:35

1 Answers1

1

The implicitly defined copy constructor of your any type just copies the IValue pointer, so both the original object and the copy will delete the same pointer. You need to write a copy constructor that actually copies the stored object.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312