0%

參考docker-gitlab這個網頁,實際餐作一次。

1
2
3
$ docker pull sameersbn/gitlab:latest
$ docker pull sameersbn/mysql:latest
$ docker pull sameersbn/redis:latest
1
$ 

紀錄一下STL裡面常用的幾種iterator

reverse_iterator

顧名思義就是將容器從後面往前的順序訪問。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
char array[] = "abcde";
using backword_iterator = reverse_iterator < char * > ;
backword_iterator it = backword_iterator(array + 5);
backword_iterator itend = backword_iterator(array);
while (it != itend)
cout << *it++;
cout << endl;
}

insert_iterator

共分三種

  • back_inserter 插入在容器最尾端,需要Container有push_back功能,所以只支援vector deque list
  • front_inserter 插入在容器最前端,需要Container有push_front功能,所以之支援deque list
  • insert_iterator 可插入在任何容器的任何位置,需要Contaner有insert功能,所有Container都支援。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iterator>
#include <iostream>
#include <list>
using namespace std;
template <typename T>
void printContainer(const list<T>& lists)
{
for (auto iter = begin(lists); iter != end(lists); ++iter)
cout << *iter;
cout << endl;
}
template <typename T>
insert_iterator<T> make_insert_iterater(T& lists, typename T::iterator iter)
{
return insert_iterator<T>(lists, iter);
}
int main()
{
int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list<int> integers;
copy(array + 5, array + 10, back_inserter(integers));
printContainer(integers);
using backword_iterator = reverse_iterator < int * >;
copy(backword_iterator(array + 5), backword_iterator(array), front_inserter(integers));
printContainer(integers);
list<int>::iterator iter = integers.begin();
iter++; iter++;
copy(array + 1, array + 3, make_insert_iterater(integers, iter));
printContainer(integers);
}

move_iterator

C++11之後新增的,顧名思義就是加上move semantics,給個範例就很明顯了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>     // std::cout
#include <iterator> // std::move_iterator
#include <vector> // std::vector
#include <string> // std::string
#include <algorithm> // std::copy

int main() {
std::vector<std::string> foo(3);
std::vector<std::string> bar{ "one", "two", "three" };

typedef std::vector<std::string>::iterator Iter;

std::copy(std::move_iterator<Iter>(bar.begin()),
std::move_iterator<Iter>(bar.end()),
foo.begin());

// bar now contains unspecified values; clear it:
bar.clear();

std::cout << "foo:";
for (std::string& x : foo) std::cout << ' ' << x;
std::cout << '\n';

return 0;
}

雖然有用過libuv,不過Boost asio可能會成為下一代C++的標準配備,還是先熟悉一下。
Boost除了Network之外,還有其他很多功能,不過此次就先以Network作介紹。
它同時支援Sync / Async兩種方式,以下是個範例。

Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <boost/asio.hpp>

using namespace boost::asio;
using namespace boost::system;
using namespace std;
int main(int argc, char* argv[])
{
io_service iosev;
ip::tcp::acceptor acceptor(iosev,
ip::tcp::endpoint(ip::tcp::v4(), 10000));
char buf[100];
for(;;)
{
ip::tcp::socket socket(iosev);
acceptor.accept(socket);
cout << socket.remote_endpoint().address() << endl;
error_code ec;
size_t len = socket.read_some(buffer(buf, 100), ec);
if (ec)
{
cout << system_error(ec).what() << endl;
break;
}
if (memcmp(buf, "Hello server", len) == 0) {
socket.write_some(buffer("Hello client"), ec);
if (ec) {
cout << system_error(ec).what() << endl;
break;
}
}
}
return 0;
}
Read more »

這兩個特色很少被提及,寫起來,免得忘了。

final

如何防止一個類別被繼承(雖然我想不到為什麼要這麼作),以前可以用虛擬繼承來防止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T>
class Base {
friend typename T;
private:
Base() {}
};
class Derived : public virtual Base <Derived> {
public:
Derived() :Base() {}
};
class MoreDerived : public Derived {
public:
MoreDerived() :Derived() {}
};

其中的MoreDerived就被編譯器禁止生成。不過這樣寫實在很麻煩,於是在C++11之後友更簡單的方式。

1
2
3
4
5
6
7
8
class Base final {
public:
Base() {}
};
class Derived : public Base {
public:
Derived() {}
};

這邊只要加上final關鍵自救能達到一樣的效果。等同於C#的sealed
同樣的,C++11也從C#跟Java借鑒了不少特色

防止虛擬函數函數被override

1
2
3
4
5
6
7
8
9
10
class Base {
public:
Base() {}
virtual void show() final {}
};
class Derived : public Base {
public:
Derived() {}
void show() {} // Compile error
};

override

override顧名思義就是檢查BaseClass之中,有沒有同樣Signature的函式宣告,如果沒有的話,就會爆錯。免得產生新的函數而不自知。

1
2
3
4
5
6
7
8
9
class Base {
public:
virtual void show(int) {}
};
class Derived : public Base {
public:
void show(int) override {}
void show(double) override {} // Compile error
};

在上面的例子中,可以看到Base沒有show(double)這個Signature的宣告,因此Compiler會報錯。
因此我們可以透過 pure virtual function在編譯時檢查每個subclass都有實做此函數,而用override來檢查這函數是在VTable中。

這是最近流行的最佳化技術之一。打破所謂的Source file隔離原則,可以在Link time時對程式作最佳化。

Without LTO

直接給個範例

demo.c
1
2
3
4
5
6
7
#include <stdio.h>
int add(int, int);
int main()
{
printf("%d\n", add(1, 1));
return 0;
}
add.c
1
2
3
4
int add(int a, int b)
{
return a + b;
}
Read more »

之前遇到一個使用情況,在unique_ptr已經存在於STL Container當中,想要把他從Container移除且回傳出被分離的unique_ptr,該怎麼做。

Original idea

原來的想法很簡單,沒考慮太多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <memory>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
template<typename Func>
unique_ptr<int> RemoveFromContainer(vector<unique_ptr<int>> &c, Func pred) {
auto it = find_if(begin(c), end(c), pred);
unique_ptr<int> ret = move(*it);
c.erase(it);
return ret;
}
int main()
{
vector<unique_ptr<int>> vec;
vec.push_back(make_unique<int>(1));
vec.push_back(make_unique<int>(2));
vec.push_back(make_unique<int>(3));
unique_ptr<int> ret = RemoveFromContainer(vec, [](const unique_ptr<int> &elem) {
return *elem == 2;
});
if (ret) cout << *ret << endl;
for (auto &elem : vec)
cout << *elem << endl;
}

注意要將unique_ptr從Container移出來需要用move,然後才能將其刪除。

Read more »

Trait有很多種形式,Scala也有Trait。不過這邊講的是Rust的Trait。Scala的Trait觀念不太一樣。
一開始是看到這篇How are Rust Traits different from Go Interfaces?,後來發現跟C++觀念有點相近,於是一起比較。

Rust trait

trait長得很像Interface,不過方式不太一樣,會在編譯時期檢查資料型態。

1
2
3
4
5
6
7
8
9
10
11
trait Foo { fn bar(&self); }

impl Foo for int { fn bar(&self) {} }
impl Foo for String { fn bar(&self) {} }

fn call_bar<T: Foo>(value: T) { value.bar() }

fn main() {
call_bar(1i);
call_bar("foo".to_string());
}
Read more »

安裝systemtap本身沒什麼,不過如何找到Debug info就沒這麼簡單了。

1
$ sudo apt-get install systemtap

以下是網路大神提供的懶人法

1
2
3
$ wget http://www.domaigne.com/download/tools/get-dbgsym
$ chmod a+x get-dbgsym
$ ./get-dbgsym

曾經試著自己編譯過,不過kernel mismatch,有時間再試吧。

雖然這題目很簡單,不過看到How to zero a buffer我嚇到了,原來我之前的觀念不一定正確。
假設我們在程式中有些敏感資料(金鑰/密碼等),希望能夠在使用之後清除掉。通常我們會這麼作。

1
2
3
4
5
6
7
8
9
void dosomethingsensitive(void)
{
uint8_t key[32];

...

/* Zero sensitive information. */
memset(key, 0, sizeof(key));
}

不過這段程式碼經過最佳化之後,最後的memset被省略不做。

Read more »

最近碰到一個困難的問題,好不容易找到解答,因此紀錄起來。
當一個Socket讀寫速度不對稱的時候,該怎麼處理。
假設Socket讀取的資料室100M/S,而寫入的速度是10M/S。
如果是Blocking I/O,OS會自動幫你處理這種狀況,難怪上網找範例程式碼都沒特別處理。
由於libuv/libevent等都是Non-blocking I/O framework,,因此無法得到有用的資訊。
翻到Linux多線程服務端編程:使用muduo C++網絡庫裡面有個地方觸動了我的靈感。利用Watermark來管理讀寫動作。
後來找到Libevent的BuffereventsPython asys IO都有類似Watermark的觀念,我想這應該是可行解。

以讀取比寫入快為例

  • 當寫入的資料量大於Hih water mark時,暫停讀取動作
  • 當剩餘的寫入資料量小於Low water mark時,重新開始讀取
    反之亦然。
    Read more »