0%

為了很多因素(降低Playform depdent / Optimization等。 GCC 跟 CLANG 都引進了一層中間層,這曾的目的是定義一個平台無關的指令集, 以老朋友hello來示範如何輸出中間產物。

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("Hello world\n");
return 0;
}
Read more »

看到濟濟篇文章的總結,寫起來,免得忘了。

do-while & continue

以下這段Code應該一堆人猜錯

1
2
3
4
5
int i = 0;
do {
std::cout << i << std::endl;
if (i < 5) continue;
} while (i++);

continue會跳到邏輯判斷的地方,而不是Block的最前端。

sizeof

sizeof是compile-time的operator,所以以下這段code的結果會是4 0

1
2
3
int i = 0;
std::cout << sizeof(i++) << std::endl;
std::cout << i << std::endl;

另外sizeof在不同的地方會有不同的表現

1
2
3
4
5
6
7
8
9
int arr[SIZE][SIZE][SIZE];
void print_sizeof(int a[SIZE][SIZE][SIZE])
{
std::cout << sizeof(a) << std::endl; // 4
std::cout << sizeof(a[0]) << std::endl; // 400
std::cout << sizeof(a[0][0]) << std::endl; // 40
}
std::cout << sizeof(arr) << std::endl; // 4000
print_sizeof(arr);

裡面最令人驚奇的是print_sizeof中的第一個輸出值是4,因為第一維的index是pointer。

Static class variable in class

1
2
3
4
5
6
7
8
9
class A {
public:
A() { cout << "A::A" << endl; }
};
class B {
static A a;
public:
B() { cout << "B::B" << endl; }
};

這邊的輸出結果沒有呼叫A的Constructor,因為a只宣告沒定義。
需要加上

1
A B::a;

如果我們沒有加上定義,這樣子是沒有問題的。

1
2
3
4
5
6
7
8
class B {
static A a;
public:
B() { cout << "B::B" << endl; }
static A getA() { return a; }
};
B b;
A a = b.getA();

因為A是個empty class所以就算沒定義也沒問題,如果不是的話就會出現編譯錯誤。

NULL pointer to an object

這段Code沒有問題

1
2
3
4
5
6
7
class A {
int x;
public:
void print() { cout << "A" << endl; }
};
A *pA = nullptr;
pA->print();

因為member function不涉及這物件的屬性任何操作,因此什麼都沒發生。

參考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,有時間再試吧。