November 30
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
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
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.
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 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
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
#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
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
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
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.