Onega's profileOnegaBlogListsNetwork Tools Help

Blog


    November 30

    why do I use alloca

    alloca function allocates memory from stack, thus is much faster than heap and is released automatically when function exit. At first look it like like declare a char array, but the difference is that you can only declare array of fixed size on stack, but you can get variable size memory (although limited by available stack size) via alloca.

    #include <windows.h>
    #include <iostream>
    #include <iomanip>
    #include <exception>
    void test_stackoverflow(int size)
    {
        std::cout << __FUNCTION__ << "("<<size<<")\n";
        char* ptr = static_cast<char*>(alloca(size));
        ptr[0]='a';
        std::cout << __FUNCTION__ << "()\n";
    }

    void test_with_std_exception()
    {
        try
        {
            for(int i=102; ;i++ )
                test_stackoverflow(i*10240);
        }
        catch (std::exception& e)
        {
            std::cout << e.what()<<std::endl;
        }

    }
    void main(int argc, char* argv[])
    {
        __try{
            for(int i=102; ;i++ )
                test_stackoverflow(i*10240);

        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            std::cout<<"Exception code 0x"<<std::hex<< _exception_code()<<std::endl;
        }
        if (argc>1)
            test_with_std_exception();
    }
    // cl -EHa overflow.cpp
    // D:\test\stl>overflow.exe
    //test_stackoverflow(1044480)
    //  Exception code 0xc00000fd

    November 17

    std::stack, std::queue and std::priority_queue

    The interesting fact is that std::queue and std::priority_queue has different interface – std::queue has front(), but std::priority_queue has top().

    #include <stack>
    #include <list>
    #include <iostream>
    #include <string>
    #include <queue>

    template<typename ContainerType>
    void fill_container(ContainerType& cnt)
    {
        cnt.push('a');
        cnt.push('0');
        cnt.push('b');
        cnt.push('c');
    }

    void main()
    {
        typedef std::stack< char, std::list<char> > char_list_stack;
        char_list_stack mystack; fill_container(mystack);
        std::cout << "\ncontent in stack:";
        while(mystack.size())
        {
            std::cout << mystack.top() << " ";
            mystack.pop();
        }

        std::queue<char, std::list<char> > myqueue;
        fill_container(myqueue);
        std::cout << "\ncontent in queue:";
        while(myqueue.size())
        {
            std::cout << myqueue.front() << " ";
            myqueue.pop();
        }

        //std::priority_queue<char, std::deque<char> > mypqueue;
        std::priority_queue<char, std::vector<char> > mypqueue;
        fill_container(mypqueue);
        std::cout << "\ncontent in priority_queue:";
        while(mypqueue.size())
        {
            std::cout << mypqueue.top() << " ";
            mypqueue.pop();
        }

    }
    // cl -EHsc stack.cpp -link -verbose:lib
    // content in stack:c b 0 a
    // content in queue:a 0 b c
    // content in priority_queue:c b a 0

    exception in ctor

    operator new return NULL if ctor throw exception, this will leads to resource leak, and other possible problem like lock is not released.

    // ctor.cpp : test throw exception in ctor.
    // cl -EHsc -d1reportSingleClassLayoutCtorWithException ctor.cpp

    #define _CRTDBG_MAP_ALLOC
    #include <tchar.h>
    #include <stdlib.h>
    #include <crtdbg.h>
    #include <iostream>
    #include <iomanip>

    class CtorWithException
    {
    public:
        CtorWithException(bool throw_exception):m_buf(new char[10240])
        {
            std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
            if (throw_exception)
            throw std::runtime_error("exception in ctor");
        }
        ~CtorWithException()
        {
            delete[] m_buf;
            std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
        }
    private:
        char* m_buf;
    };

    class TestCtorWithException
    {
    public:
        TestCtorWithException():m_buf(new char[1024*1024]),m_no_exp(false),m_has_exp(true),m_uninitialized(false)
        {
            std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
        };
        ~TestCtorWithException()
        {
            delete[] m_buf;
            std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
        };
    private:
        char *m_buf;
        CtorWithException m_no_exp;
        CtorWithException m_has_exp;
        CtorWithException m_uninitialized;
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT );
        TestCtorWithException* testobj=NULL;
        try
        {
            //TestCtorWithException test_obj;
            testobj=new TestCtorWithException;
        }
        catch (std::exception& e)
        {
            std::cout << e.what() << std::endl;
        }
        std::cout << "new return " << std::hex << testobj << std::endl;
        _CrtDumpMemoryLeaks();
        return 0;
    }
    // program output
    //CtorWithException::CtorWithException this=38cf34
    //CtorWithException::CtorWithException this=38cf38
    //CtorWithException::~CtorWithException this=38cf34
    //exception in ctor
    //new return 00000000
    //Detected memory leaks!
    //Dumping objects ->
    //{225} normal block at 0x00530068, 10240 bytes long.
    //Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
    //{203} normal block at 0x00420040, 1048576 bytes long.
    //Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
    //      Object dump complete.

    boost.program_options crash

    A program linking with libboost_program_options-vc90-mt-gd-1_35.lib crashed at desc.add_options(), but the release version worked. At last it turned out to be due to mixed usage of debug version CRT and release version CRT – the program in trouble linked to some release version library in its debug build. The interesting fact is that VC++ 2008 does not complain during compilation, but boost.program_options raised obscure run-time error.

    October 13

    custom deleter and shared_ptr

    Custom deleter can be used to manage resource other than memory via shared_ptr. Here I elaborated some usage of custom deleter.

    #include <iostream>
    #include <boost/shared_ptr.hpp>
    #include <boost/bind.hpp>
    #include <list>
    using namespace std;
    class custom_deleter_demo
    {
    public:
        custom_deleter_demo(int data):m_data(data){    }
        void custom_deleter0()
        {
            std::cout << __FUNCTION__ << " data is " << m_data << std::endl;
            delete this;
        }
        void custom_deleter1(int extra_arg)
        {
            std::cout << __FUNCTION__ << " data is " << m_data <<
            ", extra argument is " << extra_arg << std::endl;
            delete this;
        }
        static void static_custom_deleter(custom_deleter_demo* ptr)
        {
            std::cout << __FUNCTION__ << " data is " << ptr->m_data << std::endl;
            delete ptr;
        }
    private:
        ~custom_deleter_demo()
        {
            std::cout << __FUNCTION__ << " data is " << m_data << std::endl;
        }
        int m_data;
    };

    int main() {
        typedef boost::shared_ptr<custom_deleter_demo> ptr_custom_deleter;
        std::list<ptr_custom_deleter> my_list;
        my_list.push_back(ptr_custom_deleter(new custom_deleter_demo(__LINE__),
                custom_deleter_demo::static_custom_deleter));
        custom_deleter_demo* ptr_object=new custom_deleter_demo(__LINE__);
        my_list.push_back(ptr_custom_deleter(ptr_object,
                boost::bind(&custom_deleter_demo::custom_deleter0, ptr_object)) );
        ptr_object=new custom_deleter_demo(__LINE__);
        my_list.push_back(ptr_custom_deleter(ptr_object,
                boost::bind(&custom_deleter_demo::custom_deleter1, ptr_object,__LINE__)) );
        my_list.clear();
        cout << "Demo custom deleter with shared_ptr" << endl;
        return 0;
    }

    June 09

    boost::multi_index_container and boost::shared_ptr

    It is a surprise that google only returns 8 results with the following search “multi_index ordered_unique shared_ptr custom key extractor”.

    February 13

    store string in boost::circular_buffer

    #include <boost/circular_buffer.hpp>

    #include <string>

    #include <iostream>

    int _tmain(int argc, _TCHAR* argv[])

    {

    // create a circular buffer of capacity 3

    boost::circular_buffer<std::string> cb(3);

    // insert some elements into the circular buffer

    for (size_t i=0; i<cb.capacity()*2; i++)

        {

    char buf[128];

    sprintf_s(buf, "string %d", i);

    cb.push_back(std::string(buf));

        }

    std::cout << "number of elements in container: " << cb.size() << std::endl;

    std::cout << "content of the circular buffer container." << std::endl;

    for (boost::circular_buffer<std::string>::const_iterator it = cb.begin();

    it!=cb.end();

    it++)

        {

    std::cout << *it << std::endl;

        }

    return 0;

    }

    June 29

    find first bit in integer in 3 methods

    I just did a demo to find out how each method differ in performance. 3 methods are:

    method using AND operation

    method using lookup table

    method using ASM/intrinsic function

    Result:

    gccfindbitd <tect_count>
    Find bit via AND operation uses 375 msec with 10000000 numbers
    Find bit via lookup table uses 157 msec with 10000000 numbers
    Find bit via inline asm uses 62 msec with 10000000 numbers

     

     

    The code snippet is compiled by VC++ 2008 and gcc 3.4.5

    /*
    * main.cpp
    *
    *  Created on: 2008-6-27
    *      Author: onega.zhang
    */

    #include <iostream>
    #include <iomanip>
    #include <windows.h>
    int findbit1const[32];
    int findbit2const[256];
    int findbit2(int a)
    {
        unsigned char* p = (unsigned char*)&a;
        int ret = -1;
        int offset = 0;
        for (int i=0; i<4; i++)
        {
            ret = findbit2const[p[i]];
            if (ret>=0)
                return ret+offset;
            offset+=8;
        }
        return ret;
    }
    int findbit1(int a)
    {
        for(int i=0;i<32;i++)
            if ( (a & findbit1const[i]))
                return i;
        return -1;
    }

    inline int findbit3(int data)
    {
    #ifdef _MSC_VER
        __asm{bsf eax, data    }
    #else
        int r=0;// or use __builtin_ffs(data)-1;
        __asm("bsf %1, %0\n"
                "jnz 1f\n"
                "movl $-1, %0\n"
                "1:":"=r"(r):"g"(data)
                    );
        return r;
    #endif
    }

    int main(int argc, char* argv[])
    {
        findbit1const[0]=1;
        for (int i=1; i<32; i++)
        {
            findbit1const[i] = (findbit1const[i-1]<<1);
        }

        for (int i=0;i<256;i++)
        {
            findbit2const[i] = findbit1(i);
        }

        // self test, check implementation of 3 methods
        for (int i=0; i<32; i++)
        {
            int input_value = findbit1const[i];
            if (findbit1(input_value)!=i)
                std::cout << "findbit1 error, expect " << i
                << ", get " << findbit1(input_value) <<
                " input is "<< input_value << std::endl;
            if (findbit2(input_value)!=i)
                std::cout << "findbit2 error, expect " << i
                << ", get " << findbit2(input_value) <<
                " input is "<< input_value  << std::endl;
            if (findbit3(findbit1const[i])!=i)
                std::cout << "findbit3 error, expect " << i
                << ", get value " << findbit3(input_value) <<
                ", input is "<< input_value  << std::endl;
        }

        int test_count = 1000;
        DWORD start=0, stop=0;
        if (argc>1)
            test_count = atoi(argv[1]);
        std::cout << "Find position of first '1' bit in an 32bit integer"
            << " using 3 methods, by Onega. Usage:" << std::endl
            << argv[0] << " <tect_count>"<< std::endl;
        {
        start = GetTickCount();
        for(int i=0;i<test_count; i++)
            findbit1(i);
        stop = GetTickCount();
        std::cout << "Find bit via AND operation uses "
        << stop-start << " msec with " << test_count
        << " numbers" << std::endl;
        }
        {
        start = GetTickCount();
        for(int i=0;i<test_count; i++)
            findbit2(i);
        stop = GetTickCount();
        std::cout << "Find bit via lookup table uses "
            << stop-start << " msec with " << test_count
            << " numbers" << std::endl;
        }
        {
        start = GetTickCount();
        for(int i=0;i<test_count; i++)
            findbit3(i);
        stop = GetTickCount();
        std::cout << "Find bit via inline asm uses "
            << stop-start << " msec with " << test_count
            << " numbers" << std::endl;
        }
        return 0;
    }

    May 20

    boost::interprocess::mapped_region can't get size of boost::interprocess::windows_shared_memory

    User has to pass size explicitly to ctor of mapped_region, otherwise mapped_region.get_size() return 0. The boost document mentioned it, but I think the mapped_region implementation should not allow user ignore size parameters when mapped_region is working with windows_shared_memory.

    April 04

    boost.bimap and boost.multi_index container

    It is interesting that the boost group accepted some libraries that are heavily overlapped. In my opinion, bimap can be specialized in multi_index library, in fact multi_index library contains a bimap usage sample.

    March 27

    DDJ: A cross-platform plugin framework for C/C++

    Building Your Own Plugin Framework:
    Part 1, Part 2, Part 3, Part 4, Part 5