tweaking the virtual function table pointer

Discussion in 'C++' started by =?iso-8859-1?B?RnJhbmstUmVu6SBTY2jkZmVy?=, Sep 23, 2005.

  1. Case:

    -- class X has occupies tiny amount of memory:

    sizeof(X) is only a little greater than sizeof(void*).

    -- X instantiates thousands of objects and memory does matter.

    -- The class has a virtual destructor, and therefore, a pointer
    to a virtual function table.

    -- This class, now, needs a boolean variable 'boolF' which would
    cost at the very least 1 byte, which is a lot under the
    circumstances described above.

    --> idea: (1) copy the virtual function table at another place.

    (2) let the virtual function pointer point to either
    one of the virtual function tables (which are
    identical), but:

    The place where the pointer points to indicates the
    state of the 'implicitly represented' variable
    'boolF'.

    Such a setup is profitable, if

    N * sizeof(bool) > sizeof(virtual function table),

    where N = estimated number of instantiated objects.

    Does the standard impose the management of virtual function tables
    strictly enough to elaborate on such a solution? Is such a
    solution practical?

    Thanks

    Frank
    =?iso-8859-1?B?RnJhbmstUmVu6SBTY2jkZmVy?=, Sep 23, 2005
    #1
    1. Advertising

  2. Frank-René Schäfer wrote:
    > [...]
    > Does the standard impose the management of virtual function tables
    > strictly enough to elaborate on such a solution? Is such a
    > solution practical?


    The Standard says nothing about "management of virtual function tables"
    since it's outside of the realm of its concern. It's an implementation
    detail.

    V
    Victor Bazarov, Sep 23, 2005
    #2
    1. Advertising

  3. =?iso-8859-1?B?RnJhbmstUmVu6SBTY2jkZmVy?=

    Mike Wahler Guest

    "Frank-René Schäfer" <> wrote in message
    news:...
    > Case:
    >
    > -- class X has occupies tiny amount of memory:
    >
    > sizeof(X) is only a little greater than sizeof(void*).
    >
    > -- X instantiates thousands of objects and memory does matter.
    >
    > -- The class has a virtual destructor, and therefore, a pointer
    > to a virtual function table.
    >
    > -- This class, now, needs a boolean variable 'boolF' which would
    > cost at the very least 1 byte, which is a lot under the
    > circumstances described above.
    >
    > --> idea: (1) copy the virtual function table at another place.
    >
    > (2) let the virtual function pointer point to either
    > one of the virtual function tables (which are
    > identical), but:
    >
    > The place where the pointer points to indicates the
    > state of the 'implicitly represented' variable
    > 'boolF'.
    >
    > Such a setup is profitable, if
    >
    > N * sizeof(bool) > sizeof(virtual function table),
    >
    > where N = estimated number of instantiated objects.
    >
    > Does the standard impose the management of virtual function tables


    No. The standard does not at all dictate how virtual function
    behavior is implemented, only that virtual functions behave in
    a particular manner. There's no requirement to use a mechanism
    such as a 'vtable' (although afaik many/ most compilers do use them).

    > strictly enough to elaborate on such a solution? Is such a
    > solution practical?


    That depends upon your needs, but I doubt it.

    -Mike
    Mike Wahler, Sep 23, 2005
    #3
  4. * =?iso-8859-1?B?RnJhbmstUmVu6SBTY2jkZmVy?=:
    > Case:
    >
    > -- class X has occupies tiny amount of memory:
    >
    > sizeof(X) is only a little greater than sizeof(void*).
    >
    > -- X instantiates thousands of objects and memory does matter.
    >
    > -- The class has a virtual destructor, and therefore, a pointer
    > to a virtual function table.
    >
    > -- This class, now, needs a boolean variable 'boolF' which would
    > cost at the very least 1 byte, which is a lot under the
    > circumstances described above.
    >
    > --> idea: (1) copy the virtual function table at another place.
    >
    > (2) let the virtual function pointer point to either
    > one of the virtual function tables (which are
    > identical), but:
    >
    > The place where the pointer points to indicates the
    > state of the 'implicitly represented' variable
    > 'boolF'.
    >
    > Such a setup is profitable, if
    >
    > N * sizeof(bool) > sizeof(virtual function table),
    >
    > where N = estimated number of instantiated objects.
    >
    > Does the standard impose the management of virtual function tables
    > strictly enough to elaborate on such a solution?
    >
    > Is such a solution practical?


    No, the standard does not specify whether there _is_ a vtable or not.

    However, if your objects are not handled polymorphically, then simply get rid
    of that virtual destructor, and you've made room for your boolean.

    If on the other hand the objects are handled polymorphically you might
    implement the essentials of your idea by using two classes derived from a
    common base class, one representing 'false' and the other 'true'.

    Another idea can be to store the booleans externally to the objects, as a
    bitset. For that idea you need some way to easily associate each object with
    a unique index, without more memory overhead. That of course depends on your
    objects.

    And a third idea, to use the flyweight pattern, in essence to store pure data
    objects and bring the functionality to the data (or vice versa, depending on
    your point of view) when required.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Sep 23, 2005
    #4
  5. =?iso-8859-1?B?RnJhbmstUmVu6SBTY2jkZmVy?=

    Calum Grant Guest

    Frank-René Schäfer wrote:
    > Case:
    >
    > -- class X has occupies tiny amount of memory:
    >
    > sizeof(X) is only a little greater than sizeof(void*).
    >
    > -- X instantiates thousands of objects and memory does matter.
    >
    > -- The class has a virtual destructor, and therefore, a pointer
    > to a virtual function table.
    >
    > -- This class, now, needs a boolean variable 'boolF' which would
    > cost at the very least 1 byte, which is a lot under the
    > circumstances described above.
    >
    > --> idea: (1) copy the virtual function table at another place.
    >
    > (2) let the virtual function pointer point to either
    > one of the virtual function tables (which are
    > identical), but:
    >
    > The place where the pointer points to indicates the
    > state of the 'implicitly represented' variable
    > 'boolF'.
    >
    > Such a setup is profitable, if
    >
    > N * sizeof(bool) > sizeof(virtual function table),
    >
    > where N = estimated number of instantiated objects.
    >
    > Does the standard impose the management of virtual function tables
    > strictly enough to elaborate on such a solution? Is such a
    > solution practical?
    >
    > Thanks
    >
    > Frank
    >


    Flyweight (mentioned by A.Steinbach) is a good solution.

    Is there any reason why you actually need these objects instantiated
    simultaneously? I mean if you had (say) a vector<char> v, you could
    create a temporary

    myfn(ExpensiveChar(v))

    That is, only create the object when you need it, and store it
    efficiently when you don't.

    Calum
    Calum Grant, Sep 23, 2005
    #5
  6. Actually, I was considering this 'design' as a kind of 'flyweight'
    pattern,
    where the key is the pointer to the vtable.

    -- What about the typeid()-operator? Considering your second proposal,
    with twol classes, let's say "X_false", the other "X_true". How
    could I
    turn the switch for an existing object, i.e. that it's virtual
    pointer points
    to it's counterpart?

    Objects of type X_false and X_true will have the same size and
    structure,
    but is it sure, that if the tweaking works, that the deallocation is
    handled
    100% propperly?
    =?iso-8859-1?B?RnJhbmstUmVu6SBTY2jkZmVy?=, Sep 23, 2005
    #6
  7. * =?iso-8859-1?B?RnJhbmstUmVu6SBTY2jkZmVy?=:
    > Actually, I was considering this 'design' as a kind of 'flyweight'
    > pattern,


    It isn't. See the posting by Calum Grant in this thread. Or, google. ;-)


    > where the key is the pointer to the vtable.
    >
    > -- What about the typeid()-operator?


    It reports the dynamic type of an object, which with your proposed solution
    would vary.


    > Considering your second proposal,
    > with twol classes, let's say "X_false", the other "X_true". How
    > could I turn the switch for an existing object, i.e. that it's
    > virtual pointer points to it's counterpart?


    The implementation I sketched assumed, without mention, that the boolean would
    be constant for each object. However, with only polymorphic usage you can do
    dirty tricks. Not that I recommend this, and I'm not even sure whether it's
    well-defined or perhaps undefined behavior, and since you're counting _bytes_
    this solution requires a really efficient small object allocator (otherwise
    you can easily have, say, 24 bytes "invisible" overhead per object):

    #include <iostream>
    #include <stdexcept>
    #include <memory>

    class Data {};
    class SomeInterface{ public: virtual ~SomeInterface() {} };

    class Base: public SomeInterface
    {
    public:
    virtual bool boolValue() const = 0;
    virtual void setBoolValue( bool newValue ) = 0;

    Base& operator=( Base const& other )
    {
    myData = other.myData; // Could be optimized.
    setBoolValue( other.boolValue() );
    }

    static Base* Base::instanceAt( void* storage, Data const& data, bool
    aBoolValue );
    static std::auto_ptr<Base> newInstance( Data const& data, bool aBoolValue
    );

    private:
    class DerivedFalse; friend class DerivedFalse;
    class DerivedTrue; friend class DerivedTrue;

    Data myData;

    Base( Data const& data ): myData( data ) {};
    Base( Base const& ); // None.
    };

    class Base::DerivedFalse: public Base
    {
    public:
    DerivedFalse( Data const& data ): Base( data ) {}
    virtual bool boolValue() const { return false; }
    virtual void setBoolValue( bool newValue );
    };

    class Base::DerivedTrue: public Base
    {
    public:
    DerivedTrue( Data const& data ): Base( data ) {}
    virtual bool boolValue() const { return true; }
    virtual void setBoolValue( bool newValue );
    };

    Base* Base::instanceAt( void* storage, Data const& data, bool aBoolValue )
    {
    if( aBoolValue )
    {
    return new( storage ) DerivedTrue( data );
    }
    else
    {
    return new( storage ) DerivedFalse( data );
    }
    }

    std::auto_ptr<Base> Base::newInstance( Data const& data, bool aBoolValue )
    {
    // ASSERT sizeof(Base) == sizeof(Base::DerivedFalse)
    // ASSERT sizeof(Base) == sizeof(Base::DerivedTrue)
    return std::auto_ptr<Base>(
    instanceAt( new char[sizeof(Base)], data, aBoolValue )
    );
    }

    void Base::DerivedFalse::setBoolValue( bool newValue )
    {
    if( newValue != boolValue() )
    {
    Data data = myData;
    this->~DerivedFalse();
    new( this ) DerivedTrue( data );
    }
    }

    void Base::DerivedTrue::setBoolValue( bool newValue )
    {
    if( newValue != boolValue() )
    {
    Data data = myData;
    this->~DerivedTrue();
    new( this ) DerivedFalse( data );
    }
    }

    int main()
    {
    try
    {
    std::auto_ptr<Base> p( Base::newInstance( Data(), true ) );

    std::cout << sizeof( Base ) << std::endl;
    std::cout << std::boolalpha;

    std::cout << p->boolValue() << std::endl;
    p->setBoolValue( false );
    std::cout << p->boolValue() << std::endl;
    p->setBoolValue( true );
    std::cout << p->boolValue() << std::endl;
    }
    catch( std::exception const& x )
    {
    std::cerr << "!" << x.what() << std::endl;
    }
    }


    > Objects of type X_false and X_true will have the same size and
    > structure, but is it sure, that if the tweaking works, that the
    > deallocation is handled 100% propperly?


    I think so.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Sep 23, 2005
    #7
  8. * Alf P. Steinbach:
    > std::auto_ptr<Base> Base::newInstance( Data const& data, bool aBoolValue )
    > {
    > // ASSERT sizeof(Base) == sizeof(Base::DerivedFalse)
    > // ASSERT sizeof(Base) == sizeof(Base::DerivedTrue)
    > return std::auto_ptr<Base>(
    > instanceAt( new char[sizeof(Base)], data, aBoolValue )
    > );
    > }


    Forgot to fix that before posting, t'was just a raw hack. But I think you get
    the idea in spite of that formally very incorrect code -- the problem with
    this code is allocation as char array and deallocation as Base object, which
    is Not Good (TM). That must be fixed for real code.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Sep 23, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paul W
    Replies:
    0
    Views:
    401
    Paul W
    Oct 26, 2004
  2. Sandy Norton

    tweaking @decorator syntax

    Sandy Norton, Aug 4, 2004, in forum: Python
    Replies:
    14
    Views:
    484
    Dave Brueck
    Aug 6, 2004
  3. Replies:
    0
    Views:
    319
  4. Anastasios Hatzis
    Replies:
    0
    Views:
    470
    Anastasios Hatzis
    Mar 7, 2007
  5. Replies:
    0
    Views:
    308
Loading...

Share This Page