Baz
Baz

Reputation: 13125

Container implementation for complex type

I'm trying to come up with a container wrapper which stores data of the following types: bool, int, double, std::string. In addition I have a complex type which I need to store in the container. Let's call it Foo. For the sake of simplicity we'll say that Foo contains a list of ints.

My container class currently wraps an ugly and complex container type which I get from a c api. When I'm finish manipulating the data in the container, I need to copy it back to the api. It uses unions and linked lists. It is possible that I can copy this data into, for example, a std::list, but this might cause performance issues which present themselves at a later date. Therefore, my container class is not dependant on how data is actually stored in memory.

Here's a quick idea of how my container looks:

template <class T>
class Cont
{
public:
    Cont(ISetter<T>* setter)
        : _setter(setter)
    {
    }

    void sillyFunction(T t)
    {
        (*_setter)(t,0);
    }

private:
    ...
    ISetter<T>* _setter;
};

So I use a helper setter class which handles the nitty gritty of the memory. I have a number of these class but the ISetter will give you an idea of what I'm doing.

In order to deal with the Foo type, which is also stored by the c api in a rather bizarre way, I have arrived at the following setter. Again, this is just a rough example.

class IFoo
{
public:
    virtual int getMember() = 0;
};

class Foo2: public IFoo
{
public:
    virtual int getMember(){ return 1;} // dummy 
};

template<typename T> class ISetter{};
template<> class ISetter<IFoo*>
{
public:
    virtual void operator()(IFoo* value, int index) = 0;
};

template<typename T> class Setter{};
template<> class Setter2<Foo2*>: public ISetter<IFoo*>
{
public:
    virtual void operator()(IFoo* value, int index)
    {
        _list[index] = dynamic_cast<Foo2*>(value);
    }

private:
    std::vector<Foo2*> _list;
};

So I handle my Foo as an interface called IFoo. The Setter2 implementation deals with the setting in memory of my list of Foos. Setter1, missing below, deals with the ugly c api memory.

Here's an idea of these class in practice:

Foo2* f = new Foo2();
ISetter<IFoo*>* setter = new Setter2<Foo2*>();
Cont<IFoo*>* container = new Cont<IFoo*>(setter);
container->sillyFunction(f); 

When dealing with ints, for example, I do something like this instead:

int i = 10;
ISetter<int>* setter = new Setter1<int>();
Cont<int>* container = new Cont<int>(setter);
container->sillyFunction(i);

So, my question is if you think this is a good approach and what improvements you might recommend.

I use shared pointers instead of raw pointers.

Upvotes: 1

Views: 369

Answers (2)

PiotrNycz
PiotrNycz

Reputation: 24347

I would change it a little. Consider to remove all this Setter virtual-ism from your code. One of goal to introduce Templates were to have alternative to virtual-ism:

template <class T, class Setter>
class Cont
{
public:
    Cont(Setter setter = Setter())
        : _setter(setter)
    {
    }

    void sillyFunction(T t)
    {
        _setter(t,0);
    }

private:
    ...
    Setter _setter;
};

And its simple usage:

template <class IType, class Type>
class Setter2_Virtual
{
public:
    void operator()(IType* value, int index)
    {
        _list[index] = dynamic_cast<Type*>(value);
    }

private:
    std::vector<Type*> _list;
};


Cont<IFoo*, Setter2_Virtual<IFoo, Foo2> > container;
container.sillyFunction(f); 

I concentrated on Setters - but maybe you can do the same with IFoo/Foo stuff as well.

Just an idea - you do not obliged to use it after all.

Upvotes: 1

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247899

I would create a single simple Foo wrapper class which can look up members data from the C API, and present it as a coherent class. No need for messing about with interfaces, virtual functions or inheritance for that. Just a single class will do.

So for each "Foo"-entry in the C API, you create a single Foo wrapper.

Then you have simple, well-behaved type representing individual instances of the data stored in your C library.

Now just take that and put it in a std::vector.

struct Foo {
    Foo(<handle-or-pointer-to-library-data>);

    // member functions for retrieving member data from the C API
};


std::vector<int>
std::vector<bool>
std::vector<std::string>
std::vector<Foo>

As I understand your problem, that would be a simple and efficient solution.

Upvotes: 1

Related Questions