Monday, March 28, 2011

VA или ...

Была когда-то у меня задача связанная с VA. Был некий макрос:

#define del( pBuf ) del_impl( ( pBuf ), __FILE____LINE____FUNCTION__ )

детали del_impl не важны, но внутри в конце концов вызывался оператор delete. Потом я захотел модифицировать макрос, чтобы если передается опционально второй параметр – то внутри вызывался бы delete[]. С макросами это не так просто было сделать сразу. Порисёчив в инете я тогда придумал некое решение, но мне кажется что есть лучше. Вот то что тогда вышло (пример проверил в студии):

#include < stdarg.h >
#include < iostream >

#define SENTINEL -32768
template < class T >
inline void del_impl(
    T* &pBuf,
    const char*  szFile,
    unsigned int nLine,
    const char*  szFunc,
    unsigned int nCount,
    ...
    )
{
    va_list args;
    va_start(argsnCount);

    // bla bla bla...

    SENTINEL == va_arg( argsint ) ? delete pBuf : delete[] pBuf;

    pBuf = NULL;
    va_end(args);
}

#ifdef _MSC_VER
#   define del( pBuf, ... ) \
        del_impl( ( pBuf ), __FILE____LINE____FUNCTION__, \
            1, __VA_ARGS__SENTINEL )
#else
#   define del( pBuf, ... ) \
        del_impl( ( pBuf), __FILE__, __LINE__, __FUNCTION__, \
            1, ##__VA_ARGS__, SENTINEL )
#endif // _MSC_VER

class CTest
{
public:
    ~CTest( )
    {
        static int i = 0;
        std::cout << __FUNCTION__ << ++i << std::endl;
    }
};

int _tmain( int argc_TCHARargv[] )
{
    CTestp  new CTest;
    del( p );

    CTestpp = new CTest[10];
    del( pptrue );
    // del( pp ) // WRONG!
    //    in this case, in debug we will have an assert:
    //   _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); from 'dbgdel.cpp'

    return 0;
}

В общем если есть более красивое или правильнее или вообще другое решение – было бы прикольно его увидеть.

Tuesday, March 22, 2011

Задача по С++

Хорошая задача для собеседования "опытных" ребят по С++.
Допустим, у вас есть некий сторонний код интерфейсов/каллбеков, и вам нужно отнаследоваться от всех (в данном случает от двух):

// -- third part code (you can't change this)
Struct IFoo { virtual void Test() = 0; }; // you can't change this
Struct IBla { virtual void Test() = 0; }; // you can't change this
// -- end of third part code

далее нужно реализовать функцию Test для каждого интерфейса отдельно:

// your code (but it does not work rightly)
Struct CTest : public IFoo, public IBla
{
    Virtual void Test()
    {
        std::cout << "I'm a ...?" << std::endl;
    }
};

далее опять сторонний код, к примеру такой:

// -- third part code (you can't change this)
Int _tmain(int argc, _TCHAR* argv[])
{
    CTest test;

    IFoo& foo = test;
    foo.Test(); // must be: "I'm a foo" in out

    IBla& bla = test;
    bla.Test(); // must be: "I'm a bla" in out

    return 0;
}
// -- end of third part code

В общем я надеюсь задача ясна - нужно придумать как разрулить ситуацию не меняя интерфейсы и тестовый код.
Решение задачи ниже(белым по белому).

// code code code
#include < iostream >

struct IFoo { virtual void Test() = 0; };
struct IBla { virtual void Test() = 0; };

struct IFooImpl : IFoo
{
    virtual void Test() { return FooTest(); }
    virtual void FooTest() = 0;
};

struct IBlaImpl : IBla
{
    virtual void Test() { return BlaTest(); }
    virtual void BlaTest() = 0;
};

struct CTest : public IFooImpl , public IBlaImpl
{
    virtual void BlaTest() { std::cout << "I'm a bla" << std::endl; }
    virtual void FooTest() { std::cout << "I'm a foo" << std::endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    CTest test;

    IFoo& foo = test;
    foo.Test();

    IBla& bla = test;
    bla.Test();

    return 0;
}
// code code code

Saturday, March 19, 2011

object factory

Просто нереально простая и в тоже время для меня весьма приятная фабрика. Сие чудо было сотворенно под влиянием Александреску и ревью 3D движков. Приятного аппетита)

#ifndef __CMN_OBJ_FACTORY_H__
#define __CMN_OBJ_FACTORY_H__

#include "cmnNonCopyable.h"

#include < map >
#include < string >
#include < memory >
#include < assert.h >

namespace utils
{
    namespace factory
    {
        template < typename TIdentifierType, class TObjectType >
        struct default_err_policy
        {
            TObjectType* OnUnknownType( TIdentifierType )
            {
                assert( false );
                return NULL;
            }
        };

        template
        <
            typename TObjectType,
            typename TIdentifierType  = std::string,
            typename TCreatorCallback = TObjectType * ( * ) ( ),
            typename TCopyablePolicy  = noncopyable,
            template < typename, class > class error_policy = factory::default_err_policy
        >
        class object_factory
            : public error_policy < TIdentifierType, TObjectType >
            , TCopyablePolicy
        {
            class Constructor
            {
                Constructor();

            public:
                explicit Constructor( TCreatorCallback func ) : func_( func )
                { }

                template < typename TType >
                explicit Constructor( TType* dumb ) : func_( NULL ), type_creator_( new TypeCreator < TType > )
                { }

                TObjectType* operator( )( )
                {
                    return ( func_ ? func_( ) : ( type_creator_ ? type_creator_->Create() : NULL ) );
                }

            private:
                struct TypeCreatorBase
                {
                    virtual TObjectType* Create() = 0;
                };

                template < typename TType >
                struct TypeCreator
                    : public TypeCreatorBase
                    , TCopyablePolicy
                {
                    virtual TObjectType* Create()
                    {
                        return new TType();
                    }
                };

            private:
                TCreatorCallback func_;
                std::tr1::shared_ptr < TypeCreatorBase > type_creator_;
            };

            typedef std::map < TIdentifierType, Constructor > fmap;
            fmap factory_;

        public:
            template < typename TType >
            bool Register( const TIdentifierType& id )
            {
                return factory_.insert( fmap::value_type( id, Constructor( ( TType* ) NULL ) ) ).second != 0;
            }

            template < TCreatorCallback func >
            bool Register( const TIdentifierType& id )
            {
                return factory_.insert( fmap::value_type( id, Constructor( func ) ) ).second != 0;
            }

            bool Unregister( const TIdentifierType& id )
            {
                return factory_.erase( id ) != 0;
            }

            TObjectType* CreateObject( const TIdentifierType& id )
            {
                typename fmap::iterator iter = factory_.find( id );
                if ( iter != factory_.end() )
                {
                    return ( iter->second )( );
                }

                return OnUnknownType( id );
            }
        };
    } // factory
} // utils

#endif

Тест сего творения:

#include < iostream >
#include "cmnObjFactory.h"

using namespace std;
using namespace utils::factory;
//---------------------------------
struct IBase { virtual void Test() = 0; };

struct Test1 : IBase {
    Test1() { cout << "Create 1" << endl; }
    virtual void Test() { } };

struct Test2 : IBase {
    Test2(int i) { cout << "Create 2" << endl; }
    virtual void Test() { } };

IBase* Create() { return new Test2(2); }
//---------------------------------
object_factory < IBase > g_factory;

int _tmain(int argc, _TCHAR* argv[])
{
    g_factory.Register < Test1 >  ("test1");
    g_factory.Register < Create > ("test2");

    IBase* pObj1 = g_factory.CreateObject("test1");
    IBase* pObj2 = g_factory.CreateObject("test2");

    return 0;
}