2007年7月9日 星期一

Boost Pointer Container

http://www.boost.org/libs/ptr_container/doc/ptr_container.html

顧名思義就是存放pointer的container,exception-safe。以前我們會用這樣的方法來存放pointer:

std::vector<MyClass*> myvector;
myvector.push_back(new MyClass());
myvector[0]->do_something();

上面這段code還沒寫完喔,因為我們存的是pointer,所以之後還要去注意釋放那些pointer所allocate的memory。

現在Boost Pointer Container裡面有個ptr_vector可以對應std::vector

boost::ptr_vector<MyClass> myvector;
myvector.push_back(new MyClass());
myvector[0].do_something();

code有點不一樣,可以看到的是,我們無法從Pointer Container取回pointer了,這可以避免一些意外情況發生。另外,所有的Pointer Container都會在解構時自動釋放pointer所佔的記憶體。

看到這邊有人可能會想:不過是自動釋放記憶體嘛......我自己寫code都很細心,都會注意memory的釋放,這個pointer container沒多大用處嘛。不過,Pointer Container最重要的重點是exception-safe,何謂exception-safe?參考下面這一段code:

void func()
{
std::vector<MyClass*> myvector;
myvector.push_back(new MyClass());

try
{
// Exceptions may occur here
}
catch(...)
{
throw;
}

// I'm a good programmer
delete myvector[0];
}

在exception發生時,還沒到釋放memory的地方就跳出function了,這裡就會造成memory leak。雖然我們可以在catch裡都加上處理記憶體問題的code,但這樣的作法可能會非常的tedious(沒有人會想在每個catch裡都寫一次release memory的code吧?)。所以,有人會用std::auto_ptr或boost::shared_ptr這種smart pointer來解決這種問題:

std::vector<boost::shared_ptr<MyClass> > myvector;

C++ exception handling保證跳出function以前,所有的stack object都會被正常清除。所以上述的smart pointer都能夠保證在exception發生時,自動釋放pointer所指的memory。不過,使用smart pointer會多出一些overhead,而Pointer Container內部的實做則是直接將指標轉換成void*來儲存,顯然比smart pointer的效率要高。

基本上每個STL container在Boost Pointer Container都有互相對應的類別可以使用,例如vector對應ptr_vector,map對應ptr_map,操作方法也一樣,還擴充了一些便利的方法,例如我們可以直接用ptr_map.insert(k, v),不必像以前的std::map還要先create出一個pair object。

2007年7月4日 星期三

ClickClickClick的後續......

Click*3續觀察 : 圖形驗證與網路分工

Mr./Ms. Days上的一篇文章,詳細的解說了各個兵器的技術細節。

原本以為只是一個無聊遊戲,就像以前有一個自動練功的online game,只要掛著縮小到系統列就會自動升級,非常的空虛......那時候剛開始也是很流行,不過沒多久鄉民們就玩膩了。這次的click*3巧妙的把競爭層級拉到國與國之間的戰爭,因此在民族情感的發酵作用下,各國鄉民(宅宅?)們前仆後繼,就算是如此空虛的滑鼠點擊比賽也一直樂此不疲。

值得一提的是,網站主人並沒有刻意限制web robot(或許這才是他的目的?),於是讓各方人馬相繼開發出各種不錯的自動化兵器,看起來還蠻有趣的耶。真希望我還是學生,那我就有時間可以來玩玩這個了......

2007年7月2日 星期一

青山瀑布

在台北縣石門鄉,很好走的山路,沿途都是樹蔭,瀑布水量大,而且底下沒有深潭,比較適合玩水。



















還有人直接在瀑布底下作SPA...




















樹蔭非常多,多到會冷......


























6/30從青山瀑布下來後,順道去淡水花海節,非常後悔......花種少不說,一堆雜草都沒有清掉,儼然就像是把花種撒下去任它長一樣。而且因為烈日照射,唯一可以看的向日葵都枯乾的差不多了,還有......連個主題攤位都沒有,就是一堆枯掉的野花,和很多賣涼的攤販,總之我建議沒事不要去啥花海節了。

態度問題

蔡明里的棒球相對論


最近常常在想,有人就是從來不會檢討自己,失敗的原因絕對是其他因素。愈來愈對這種態度感觸良多,沒想到今天看一下Yahoo的Blog摩人,就看到蔡明里的文章一開頭就講到跟我一樣的觀點,這該說是巧合,還是真的很多這種人呢?

古人說:「滿招損,謙受益」,講是這樣講,可以做到的好像不多,我有時候也是很自命清高,不知道在屌什麼的樣子XD

2007年6月29日 星期五

軟體工程師最高境界

真神人也。

軟體才是登峰造極的關鍵

最近iPhone很出名,媒體幾乎都不約而同的讚美=.=...但是也有人提出反駁,指明iPhone的一些功能明明不怎麼樣,例如相機畫素不足或是不支援GPS之類的,相較之下台灣宏達電的手機在功能上反而更剩iPhone一籌呢。

但iPhone之所以會那麼受眾人喜愛,卻不是沒有原因的。看過iPhone的實機demo,真的會不禁讚嘆:這種質感,這種流暢度,真的只是一隻手機嗎XD。畫面精美就不用說了,用手指可以控制整個網頁,翻轉90度字會跟著轉,usability實在是達到出神入化的境界了。台灣代工業很強沒錯,但是軟體才是登峰造極的關鍵啊。硬體功能愈來愈強,到了某一個程度以後,能夠脫穎而出得到消費者青睞的,就只有搭配超強軟體的硬體了。

軟體業所擁有的先天優勢應該不用多說了,但這是一條漫長辛苦的路,很少公司願意等那麼久的時間。台灣現在的軟體業大部分只能靠政府案子過活,做的是軟體代工業(代工業比較快獲利,似乎很受台灣老闆喜愛),但是做事方法又不如印度的專業,整個就是毫無前景可言。政府似乎無法提出有效的解決方案,只是不停的發案試著要餵飽這些"軟體公司",但是古有名言,給他魚吃不如教他捕魚,這句話還蠻有道理的=.=。軟體業找不到人才也是原因之一,因為人才都跑去會賺大錢的行業去了,我覺得台灣可以仿照韓國政府的作法,進來遊戲軟體業不用當兵這樣,因為台灣年輕人真的很不喜歡當兵,這樣一定可以找到很多人才的,難怪韓國OLG這麼囂張=.=

2007年6月25日 星期一

Boost Thread

http://www.boost.org/doc/html/thread.html

Boost也提供了跨平台的多執行緒函式庫,該有的都有(R/W mutex還有問題,還沒正式納入),不過跟普通的多執行緒函式庫有點不同

1. 啟動方法
使用pthread的programmer會用以下方法啟動一個 thread

pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

start_routine就是thread的進入點,arg是要傳入的參數,因為只能傳一個參數,所以我們通常都是把所有參數擠在一個struct裡面......

Boost Thread是在建立thread物件時啟動一個執行緒的

boost::thread *mythread = new boost::thread(&threadfunc);

跟 一般不同的是,Boost Thread是接受Boost Function來當作thread的進入點,而不是一般的function pointer而已,上面範例的function pointer只是Boost Function的其中一種type而已, 所以, 我們可以輕鬆做到以下這種事:

struct MyClass
{
void threadfunc() {// do something}
};

int main()
{
MyClass m;
boost::thread mythread(boost::bind(&MyClass::threadfunc, &m));
// Wait for the thread...
}


直 接把non-static member function當成thread的進入點!!在以前pthread的時代,想要跑non-static member function非常麻煩,通常要寫個static wrapper之類的......拜Boost Function和Boost Bind之賜,這兩者與Boost Thread的完美結合,讓C++ programmer的生活更輕鬆了!!

有人可能已經發現了,Boost Thread在創造thread的時候,沒有地方可以傳參數進去阿!!Well,有了Boost Bind,這根本就不是問題,還能做的比以前更好。

struct MyClass
{
void threadfunc(int a, double b) {}
};

int main()
{
MyClass m;
boost::thread mythread(
boost::bind(&MyClass::threadfunc, &m, 1, 2.2));
// Wait for the thread
}



不像以前只能傳void*參數,使用bind想要傳幾個都可以,而且還是type-safe的方式。不過,既然都可以bind member function了,把參數當作member variable的寫法可能比較好

struct MyClass
{
void threadfunc() {}
int m_a;
double m_b;
};

int main()
{
MyClass m;
m.m_a = 1;
m.m_b = 2.2;
boost::thread mythread(boost::bind(&MyClass::threadfunc, &m));
// Wait for the thread
}


2. Mutex的概念

以前在pthread我們都會這樣來使用mutex

// declare mutex
pthread_mutex_t m;
pthread_mutex_init(&m, NULL);

void threadfunc(void* param)
pthread_mutex_lock(&m);
// Only one can enter here...
pthread_mutex_unlock(&m);
}


Boost Thread則是把lock當成一個物件,建構出來時表示鎖住一個mutex,解構表示解鎖一個mutex。

// declare mutex
boost::mutex m;

void threadfunc()
boost::mutex::scoped_lock lock(m);
// On exiting this function, the mutex is unlocked
}


由 於lock是stack-allocated的物件,所以在function結束後,lock會自動被摧毀,mutex就會處於unlocked狀態。 Boost Thread的lock都不保證thread-safe,其實它最好應該都被使用在stack裡,thread之間只要share mutex就可以了。

int threadfunc()
{
{
// The first critical section
boost::mutex::scoped_lock lock(m);
// do something
}
{
// The second critical section
boost::mutex::scoped_lock lock(m);
//do something
}
}


把critical section用括號包起來,然後在最前面創造一個lock,這樣就可以保證這個block的thread-safe了,這樣的寫法比較直覺而且簡潔多了,不會再像以前一樣忘記unlock mutex......

Boost Thread也有一些不足,例如沒有r/w mutex和thread termination。在很多thread lib裡,thread termination通常會牽涉到thread-safe的問題,所以大多數都會有個warning提醒programmer最好不要使用thread termination以避免發生問題(例如memory leak)。事實上,thread termination最好自己在thread裡面implement,才是最保險的作法。