Boost logo

Boost :

Subject: [boost] [cpo-proposal] About mixout container for polymorphic objects
From: Santiago Tapia (santiago.tapia_at_[hidden])
Date: 2013-09-17 08:46:04


Hi all,

I have design a new concept of container to be part of the cpo library.

In summary, those containers will break down the inserted objects into
some elementary parts.

Why do that?
Short answer: to save memory.
Long answer: Because the alignment requirement of data members
in an object could be very different, in a range from 1 byte to 16 bytes,
structs or classes use padding to provide the correct location for members.
That means an object size could be significantly greater than the sum
of its members sizes. Even more, when dealing with polymorphic objects,
the size is increased a little more due to the pointer to the table
of virtual methods.

I will try to outline the alternative solution, obviously, the implementation
will be part of the container, the user will not need to know the details.

---- Example:-----

#include <cstdlib>
#include <iostream>
#include <vector>

class output
{
public:
    virtual void print(std::ostream& out) = 0;
};

class integer {
public:
    integer(short a_ = 0) : a(a_) { }
    short a;
};

class character {
public:
    character(char c_ = 'a') : c(c_) { }
    char c;
};

class data {
public:
    data(double x_ = 0) : x(x_) { }
    double x;
};

class my_object :
    public integer,
    public data,
    public character,
    public output
{
public:
    my_object(int show = 1)
        : integer(rand() % 100)
        , data(1.0*rand()/RAND_MAX)
        , character('a' + rand() % 10)
    {
        if (show) print(std::cout);
    }

    virtual void print(std::ostream& out)
    {
        std::cout << a << "\t" << x << " \t" << c << "\n";
    }
};

void insert( std::vector<integer>& v_int,
            std::vector<data>& v_data,
            std::vector<character>& v_char,
            const my_object& o)
{
    v_int.push_back( o );
    v_data.push_back( o );
    v_char.push_back( o );
}

void iterate( std::vector<integer>& v_int,
              std::vector<data>& v_data,
              std::vector<character>& v_char
              )
{
    my_object o(0);
    unsigned i;
    for ( i = 0; i < v_int.size(); ++i)
    {
        static_cast<integer&>( o ) = v_int[i];
        static_cast<data&>( o ) = v_data[i];
        static_cast<character&>( o ) = v_char[i];
        o.print(std::cout);
    }
}

int main(int, char**)
{
    std::cout << "sizeof(my_object): "
              << sizeof(my_object) << "\n";

    std::vector<integer> v_int;
    std::vector<data> v_data;
    std::vector<character> v_char;

    std::cout << "--- inserting (random) objects ---\n";
    unsigned i;
    for ( i = 0; i < 5; ++ i )
    {
        insert( v_int, v_data, v_char, my_object() );
    }

    std::cout << "--- show content ---\n";
    iterate(v_int, v_data, v_char);

    return 0;
}

---- Output: (32 bit PC) ----

sizeof(my_object): 20
--- inserting (random) objects ---
83 0.394383 h
15 0.911647 f
86 0.76823 j
21 0.477397 h
90 0.513401 d
--- show content ---
83 0.394383 h
15 0.911647 f
86 0.76823 j
21 0.477397 h
90 0.513401 d

Final comment.

In this example, all the std::vector objects will be part of the
mixout container. The user will only use the insert method
and the container iterator that will dereference to output&
(template parameter in the container).

Just in this simple example the implementation saves
aproximately n* (20 - (8+2+1) = 9) bytes, being n
the number of instances of my_object.

Comments are wellcome.

Best regards,

   Santiago Tapia


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk