<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
<link>http://blog.roodo.com/rocksaying/archives/3679815.html/</link>
<description><![CDATA[Tags: C++ STL

最近在練習使用 C++ STL 中的 Container 功能。嗯，寫著寫著，覺得很不順手啊。例如不能用 Vector/Set/Map 直接建表。Stack 的 pop() 方法沒有回傳值；我用 C 寫的 stack 功能， pop() 是會推一個值出來的。


挑了兩個 STL Container 的練習程式碼，再用 Ruby 寫一段相同的。兩相比較，也算在吐槽吧。

]]>
	</description>
<language>zh-tw</language>
<generator>Roodo Blog System</generator>
<copyright>All Rights Reserved</copyright>
<atom:link href="http://blog.roodo.com/rocksaying/archives/3679815-comment.xml" rel="self" type="application/rss+xml" />
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[Another similar library.
<a href='http://www.boost.org/libs/assign/doc/index.html' rel='nofollow'>http://www.boost.org/libs/assign/doc/index.html</a>.]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-15349953</guid>
		<category>文章回應</category>
	<pubDate>Sat, 22 Dec 2007 17:25:57 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[InitUtil:An STL Container Initialization library
<a href='http://www.bdsoft.com/tools/initutil.html' rel='nofollow'><a href='http://www.bdsoft.com/tools/initutil.html' rel='nofollow'><a href='http://www.bdsoft.com/tools/initutil.html' rel='nofollow'>http://www.bdsoft.com/tools/initutil.html</a></a></a>

可能是你要的.]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-15349937</guid>
		<category>文章回應</category>
	<pubDate>Sat, 22 Dec 2007 17:22:48 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[類推，我的例子可以寫成:
char* ps = "Hello";
std::vector vec2(ps, ps+strlen(ps));

嗯，用指標做為容器建構初始值的寫法，應該是最直接的方式了。如果要讓容器建表像陣列一樣，那就要在語法上做修改了。算了，C++沒有必要這麼做。

Ruby 也可以用 str[pos] 的方式取出一個字元(char)。只是別忘了， char 的意義就是一個整數，所以 Ruby 的  str[pos] 之值是一個整數，而不是字串(string)。]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-12682515</guid>
		<category>文章回應</category>
	<pubDate>Tue, 24 Jul 2007 16:46:02 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[std::basic_string 也是一個容器, 和 std::vector 同樣都是有著 Random Access Container, Sequence 的容器, 通常我是視為同一類型的東西來處理, 所以我在我自己的應用上, 會選擇符合我需要特性的來處理, 像
char *tmp_string = "Hello";
std::vector&lt;char&gt; vec(tmp_string, tmp_string + strlen(tmp_strlen));
和
std::basic_string&lt;char&gt; vec("Hello");
兩個比起來, 我會選擇用後者的方式來建立, 而且這兩個處理方式也很類似, 不用因為操作的對象是 vector 或是 string 而有太大的差別(除了用到 string 特有的方式例外)

其實, 在給的 ruby 範例裡, 也是必需把 string 切割成 array(string) 才能對每一個字元做處理(就我所用過的 script 語言裡, 只有 php 可以直接對字串取出一個字元的動作: $str[$pos]), 比擬成用 STL 的話, 就是先從字串生成暫時的 std::vector&lt;char&gt; 物件, 再使用 for_each 方法對每一個 vector 所包含的 char 做處理, 這兩種本質其實是相去不遠的

至於不能用陣列作初始值? 當然那只是語法的問題, C++ 沒有方法可以用"匿名"陣列做出來類似 vector&lt;char&gt; vec = "Hello"; 或是 vector&lt;int&gt; vec = { 1, 2, 3 }; 這種東西, 所以 STL 也不可能超越這種限制, 但是如果是從已經有值的"具名"陣列來建立的話, 可以參考 <a href='http://www.sgi.com/tech/stl/Vector.html' rel='nofollow'>http://www.sgi.com/tech/stl/Vector.html</a>, std::vector 有一個方法是 template &lt;class InputIterator&gt; vector(InputIterator, InputIterator) [Creates a vector with a copy of a range.]
這個就是說, 我可以給一個陣列的起始值和它的終點來建立一個新的 vector, 比方說
int initial_array[3] = { 1, 2, 3 };
std::vector&lt;int&gt; vec(initial_array, initial_array + 3);
來做出內容是 { 1, 2, 3 } 的 vector, 至於不能用"匿名"陣列來做是好是壞, 對我來說就只是麻煩一點要多寫一些東西而已, 倒也沒什麼]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-12263725</guid>
		<category>文章回應</category>
	<pubDate>Sun, 22 Jul 2007 21:53:08 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[maniac said: '對於 "Hello" 來說, 它可以看做是一個陣列, 但是也是可以看做一個字串.'

雖然我第一個例子用的是 "Hello" ，但我原本就是要練習用容器建表、查表和走訪，而不是練習字串處理。如果我用 string 就沒有這個練習效果了。

關於直接建表的事。在我接觸 STL 之前，我原本習慣用陣列建表，然後直接把陣列作為建構子的初始值。以前的做法，類似用陣列配 Algorithms 實作一個 class 。而不是先建構容器，再一一指派。所以一開始用 STL 的 Container 時，我對它不能直接用陣列作初始值這點感到不可思議。我一直以為它可以這麼做。]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11652443</guid>
		<category>文章回應</category>
	<pubDate>Fri, 20 Jul 2007 15:01:43 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[我不知道為什麼一定要把 C 的觀念硬套在 STL 上, STL 裡沒有陣列這種東西, 比較接近的是 Random Access Container 這類的 Container, 依照要求的話, 我會選用 std::basic_string&lt;char&gt; 而不是 std::vector&lt;char&gt;(這兩者都是 Random Access Container), 再來對於 "Hello" 來說, 它可以看做是一個陣列, 但是也是可以看做一個字串, 既然是字串的話, 當然用 std::basic_string&lt;char&gt; 下去處理會是最好的選擇

而第二個例子, 要達到 key =&gt; value 這個要求, 對映到 STL 上的就是 Pair Associative Container, 底下只有 map/multimap 可以選(在 SGI STL 裡, 還有 hash_map 和 hash_multimap 可用), 所以當然 map 是首選

至於不能很簡單的設值, 就只是語法的問題, 因為 C++ 先天的限制, 不可能很簡單的做到像是 std::vector&lt;char&gt; tmp = { 1, 2, 3 }; 這種事, 要嘛就是建立出來一個慢慢設, 要嘛就是先生出一個有初始值的 char[], 然後透過 std::vector(InputIterator begin, InputIterator end) 來建立, 那這是不是算弱項, 可能吧, 因為要多寫一堆東西, 看起來就不好看

至於 pop 的問題, 如果真的需要回傳的話, 也可以自己寫一個 function 來做相同的事:
template&lt;class C&gt; C::value_type pop(C& c) {
  C::value_type tmp = c.back();
  c.pop_back();
  return tmp;
}
也不是不行啊, 不可能每一個函式庫都能滿足所有的需求的]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11644671</guid>
		<category>文章回應</category>
	<pubDate>Fri, 20 Jul 2007 13:56:25 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[關於第一個例子為何用 vector ？
理由很簡單，因為 "Hello" 是一個「陣列」。

一個陣列，我們可以直接建表:
int ar = {1,2,3,4,5};

一個 vector，頂多只能指定每個元素的初值。
vector&lt;int&gt; vec(5,0);
然後重複:
vec[0] = 1; 
vec[1] = 2;
...

cf 所提供的第二個例子也一樣:
map＜string, string＞ clr_tbl;
clr_tbl["black"] = "#ffffff";
clr_tbl["white"] = "#000000";

這是一個令我覺得煩人的程式碼重複動作。

至於鍵值的排序，這點倒不在我的需求中。所以用 vector + pair 也成。但 vector 沒有 find() ，所以還要再給它一個 find 的 Algorithms 。但這牽涉到搜尋的效率問題。

Ruby 中的 table ，鍵值不排序，但搜尋是用雜湊法。考量搜尋與插入效率，在 STL 中，最接近的就是 Map 。List的話，少了個鍵值雜湊表，搜尋效率力有未逮。

關於 pop()。在 C 語言中，我實作的方式是給一個參數，如 pop(void*elm)。如果引數為 NULL ，直接丟棄；否則存入並回傳。這種寫法在 STL 中被視為不安全的。如果要回傳，那麼還要考慮複製或參照等事，確實沒效率。

其實，我用的例子應該算敲在 STL 的弱項上。對老練的 C 程序員而言，不用 STL 反而寫起來更簡單。就像 cf 說「直接string[][]配合STL的algorithms來做比較會更適合」。

關於polymorphism與generic。

從語法與語意看，動態語言的語法其實就是泛型的。它們只是因為沒有編譯動作，而不得不 late binding 。並不得不仰賴其他的處理策略。參考《<a href="http://blog.roodo.com/rocksaying/archives/3528035.html">Use C/C++ with Dynamic Languages is Easier Than Pure C++</a>》及《<a href="http://blog.roodo.com/rocksaying/archives/3556355.html">個體之間協議互動行為的多種形式</a>》。

我也可以換另一種說法，若從泛型與編譯器的關係來看，沒有編譯器的動態語言環境不需要像 template 這類的泛型功能。See also: <a href="http://www.approximity.com/ruby/Comparison_rb_st_m_java.html">Ruby versus Smalltalk versus ...</a>. 所以 cf 說「我還沒有在其他的地方看過」是很合理的，因為 Ruby, Perl, JavaScript 等動態語言中用不著。]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11585741</guid>
		<category>文章回應</category>
	<pubDate>Thu, 19 Jul 2007 16:37:31 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[我本來也是用 copy, 不過要硬要和 ruby 對照的話, 就全改為 for_each 了
不過 cf 的第二個例子輸出是沒有合要求的哦(當然, 寫一個 function 來做是最簡單的) :p]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11577761</guid>
		<category>文章回應</category>
	<pubDate>Thu, 19 Jul 2007 13:33:07 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[另外pop() 方法沒有回傳值這碼子事
算是STL兼顧效能和彈性的一點,十分合理喔
"Generic Programming and the STL"的9.2.3 Back Insertion Sequence有講到]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11566317</guid>
	<author>cfchou_at_gmail(cf)</author>	<category>文章回應</category>
	<pubDate>Thu, 19 Jul 2007 11:24:21 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[我想第一個例子可以寫的更STL
        string s("hello");
        vector＜char＞ vec(s.begin(), s.end());
        copy(vec.begin(), vec.end(), ostream_iterator＜char＞(cout, "\n"));
        transform(vec.rbegin(), vec.rend(), ostream_iterator＜char＞(cout, "\n"), ptr_fun(::toupper));



第二個例子可以這樣做

map＜string, string＞ clr_tbl; //註一
clr_tbl["black"] = "#ffffff";
clr_tbl["white"] = "#000000";
clr_tbl["blue"] = "#0000ff";
clr_tbl["red"] = "#ff0000";
clr_tbl["green"] = "#00ff00";

transform(clr_tbl.begin(), clr_tbl.end(), ostream_iterator＜string＞(cout, "\n"), select2nd＜map＜string, string＞::value_type＞()); //註二
if(clr_tbl.find("blue") != clr_tbl.end()) cout ＜＜ "blue is " ＜＜ clr_tbl["blue"] ＜＜ endl;


註一
像這樣也可以啊
pair＜string, string＞ tbl[] = { make_pair("black", "#ffffff"), make_pair("white", "#000000") };
map＜string, string＞ clr_tbl(tbl, tbl + 2);

註二
假如不是用SGI STL的話很可能沒有他的select2nd, 但是可以自己仿造一個
template ＜typename T1, typename T2＞ T2 simu_sgi_select2nd(pair＜T1, T2＞ const & tmp)
{
        return tmp.second;
}
transform(clr_tbl.begin(), clr_tbl.end(), ostream_iterator＜string＞(cout, "\n"), ptr_fun(simu_sgi_select2nd＜string, string＞));

註三
其實拿STL map來跟純粹的table來比並不太適合
map是sorted的,如果Ruby的這樣一個table沒有sorted(如果啦,目前還沒時間研究Ruby)
那麼我會覺得直接拿vector＜pair＜string, string＞＞ or list＜pair＜string, string＞＞甚至
直接string[][]配合STL的algorithms來做比較會更適合



老實說寫這短短幾行東西還搞蠻久的(下班還賴著不走吹冷氣是怎樣......)
因為我跟STL還不熟
那就是他接受度不高的原因(你得先跟它裝熟)
但是一旦了解它的觀念(literally, Concept, 就是"Generic Programming and the STL"這本看懂的意思啦)
就會發現用它真的跟組裝樂高很像, 而STL定義軟體元件的方式真讓人大開眼界......
STL和template可以達到generic
指的不單針對c++ built-in type而是還有自訂型別可以共用所有組件
STL有的不只是效能高的container還有其他組件iterator, function object, algorithm, adaptor......
又可以擴充或抽換它們
從這些面向定義軟體元件
我還沒有在其他的地方看過


我不是了解很多其他的語言
動態語言用一個general object來承接object
在runtime的時候再去依照物件(late binding)的實際支援method與否來決定結果(runtime error?)
仍然是polymorphism的味道較重
並不算是generic
至少不算是靜態語言中的generic
我覺得STL(C++ template)比較像是不失去靜態語言優點(solid)為前提追求靜態語言中最大的彈性

但是這個是動態語言和靜態語言基本的特性不同, 無關優劣]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11558653</guid>
	<author>cfchou_at_gmail(cf)</author>	<category>文章回應</category>
	<pubDate>Thu, 19 Jul 2007 11:00:38 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[我是覺得在這兩個語言的設計理念就有差別, 所以在 C++ 裡面必需要用一些比較仔細(或者是囉哩吧嗦)的方式來處理, 好處是可以想的更仔細一點, 壞處也是要想的很仔細(像什麼型態處理等等, 一個錯就各個錯), 而 ruby(perl, php 等等)裡就可以用一些語言上先天的優勢來簡化, 但壞處就有可能是會有地方想不周延或是有一些誤解的可能性, 各有各的好, 各有各的差. 對我來說, 能夠依情況找到適合自己用的語言就好了, 我也不會想要去計較哪一個比較麻煩哪一個比較簡單 :p]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11433135</guid>
		<category>文章回應</category>
	<pubDate>Wed, 18 Jul 2007 21:21:49 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[至於第二個, 因為語法的限制, C++ 沒定義也無法做這種神奇的"擴充"(就算是 macro 也做不到), 所以得乖乖的一個一個加進去, 不過 map 可以使用 map[key] = value 的方式來設定值和 map[key] 來取值, 所以上例我會改成這樣子:
---------------------
#include &lt;iostream&gt;
#include &lt;iomanip&gt;
#include &lt;map&gt;
#include &lt;algorithm&gt;
#include &lt;string&gt;

static void print_map(const std::map&lt;std::string, std::string&gt;::value_type& data)
{
  //printf("%-10s =&gt; %-10s\n", data.first.c_str(), data.second.c_str());
  std::cout &lt;&lt; std::setiosflags(std::ios::left) &lt;&lt; std::setw(10) &lt;&lt; data.first
             &lt;&lt; " =&gt; " &lt;&lt; std::setw(7) &lt;&lt; data.second &lt;&lt; std::endl;
}

int main()
{
  char* ss[] = {
    "black",   "#ffffff",
    "white",   "#000",
    "blue",    "#0000ff",
    "red",     "#ff0000",
    "green",   "#00ff00",
    NULL
  };
  std::map&lt;std::string, std::string&gt; myMap;

  for(char **q = ss; *q; q += 2)
    myMap[*q] = *(q+1);

  for_each(myMap.begin(), myMap.end(), print_map);

  //這地方必需要用 find, 要不然會多建一個 myMap["blue"], 如果 blue 不存在的話
  if(myMap.find("blue") != myMap.end())
    std::cout &lt;&lt; "'blue' Find! It's value is " &lt;&lt; myMap["blue"] &lt;&lt; std::endl;
}]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11429197</guid>
		<category>文章回應</category>
	<pubDate>Wed, 18 Jul 2007 20:56:21 +0800</pubDate>
</item>
<item>
	<title>回應：STL Vector/Map 的使用練習, 附 Ruby 對照程式碼</title>
	<description><![CDATA[C++ 和 ruby 設計理念的不同, 所以程式寫起來也不會一樣, 不過我很好奇的是, 像第一個例子明明就應該是用 std::string 為什麼一定要用 vector (vec 是 std::string, vec.split('') 之後才算是 std::vector), 當然要做也是可以, 我自己改的程式如下:
-------------
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
#include &lt;string&gt;

static void make_upper(char& c)
{
  c = (c &gt;= 'a' && c &lt;= 'z')? (c - 0x20): c;
}

static void print_char(const char& c)
{
  std::cout &lt;&lt; c &lt;&lt; "\n";
}

int main()
{
  std::string ps("Hello");
  std::vector&lt;char&gt; vec(ps.begin(), ps.end());
  //上面兩行在這例子中也可以直接換成下面這個
  //std::string vec("Hello");
  for_each(vec.begin(), vec.end(), print_char);
  for_each(vec.begin(), vec.end(), make_upper);
  for_each(vec.rbegin(), vec.rend(), print_char);
  return 0;
}]]>
	</description>
	<link>http://blog.roodo.com/rocksaying/archives/3679815.html</link>
	<guid>http://blog.roodo.com/rocksaying/archives/3679815.html#comment-11428123</guid>
		<category>文章回應</category>
	<pubDate>Wed, 18 Jul 2007 20:44:36 +0800</pubDate>
</item>
</channel>
</rss>