求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
 
c++0x 学习笔记
 

2010-10-12 作者:feng wang 来源:feng wang的blog

 

1 ---- auto

auto : 类型自动推导 ( type deduction )

考虑下边这一行程序

1 auto a1 = 1;

由于 auto 的自动类型推导,a1 自动被编译器识别为 int 类型。更一般的使用方式是这样的:

1 auto a1 = expression;

也就是说,有了auto之后,变量类型可以由编译器自动从初始化的表达式中识别出来:

1 int f();
2 auto a1 = f();

对模板也有用:

1 template<typename T1, typename T2>
2 double sum( T1& t1, T2& t2 )
3 {
4     auto ans = t1 + t2;
5     return ans;
6 }

这看起来有些无聊而且降低了程序的可读性,不过在类型相当复杂的时候非常有用 :

1 std::map<std::string, std::string> m;
2 //for ( std::map<std::string, std::string>::iterator i = m.begin(); i != m.end(); ++i )
3 for ( auto i = m.begin(); i != m.end(); ++i )
4     ...

而且,得益于 c++0x 新型的 for 循环控制,更方便的写法是:

1 for ( auto i : m )
2     ...

当然,如果想修改 m 元素的内容,就要用引用:

1 for ( auto& i : m )
2     ...
更进一步

auto 可以与 static,const,volatile,* 和 & 等一起用:

1 int f();
2 auto i1 = f();
3 const auto i2 = f();
4 const auto& = f();

再如:

1 int* f();
2 auto i = f();
3 auto* i = f();
4 const auto* i = f();

碰到引用时跟指针稍微有些区别:

1 int& f();
2 auto i1 = f(); 
3 auto& i2 = f();
4 const auto& i3 = f();

上边变量 i1 的类型是 int ,不是 int& 。

auto 在涉及到虚拟继承时候类型推导也没有什么问题:

01 struct b
02 {
03     virtual void operator()() const
04     {
05         cout << "b()()\n";
06     }
07 };
08   
09 struct d : b
10 {
11     virtual void operator()() const
12     {
13         cout << "d()()\n";
14     }
15 };
16   
17     auto p1 = new d;
18     (*p1)();
19     auto p2 = p1;
20     (*p2)();
21   
22     b* p3 = new d;
23     auto p4 = p3;
24     (*p4)();

输出都是 d()() 。

auto 直接初始化写法是非常容易上手的:

1 auto i = 1;
2 const auto i = 1;
3 static auto i = 1;
4 const auto& i = 1;

包括指针初始化:

1 int * i = new int(1);
2 auto i = new auto(1);
3 auto* i = new auto(1);

上边三句执行动作完全一样。

有多个变量要一起 auto 也行:

1 auto i = 1, j = 2;
2 auto i = 1, *j = &i;
1 auto k = 0;
2 auto* i = &k, j = 1;

只要不试图调戏编译器就可以:

1 auto i = &i;//error
2 auto i = 1, j = 1.0;//error
更多

一个比较无聊的用法可以是这样的:

1 auto int i;

变量 i 被定义为 int 类型,不需要初始化参量。

碰到数组时候稍微尴尬点:

1 auto v1 = {1, 2, 3};
2 auto v1[3] = {1, 2, 3};//error
3 auto v1[] = {1, 2, 3}; //error
4   
5 int v[3];
6 auto v2 = v;
7 auto v2[3] = v;//error
8 auto v2[] = v; //error

编译环境:

linux 2.6.35

g++ 4.5

编译选项:

-std=c++0x

完整编译:

g++ –o test test.cc -std=c++0x

2 ---- 多线程(1) -- 启动线程

编译环境

编译器: g++ 4.5

编译选项: -std=c++0x

链接选项: –pthread

完整编译链接命令: g++ –O2 –o example example.cc -std=c++0x -pthread

头文件:

条目 头文件
thread <thread>
Mutual exclusion <mutex>
Condition variables <condition_variable>
Futures <future>

a 线程创建

I 从函数中创建

如果想在一个线程中执行一个函数 f ,那么这个线程可以这样创建:

1 std::thread t( f );
1   

如果函数有参数,那么直接把参数列在后边即可:

1 void hello_from( const char* str const )
2 {
3    std::cout << "hello from " << str << "\n";
4 }
5 std::thread t( hello_from, "thread t" );
1   

多个参数的函数也是如此:

1 void max( const long m, const long n )
2 {
3     std::cout << "max(" << m << ", " << n << ")=" << (m>n?m:n) << "\n";
4 }
5 std::thread t( max, 13, 31 );
1   

可以依此类推到3个、4个……参数的函数情形。

只要不把 main 函数也弄进去,编译器统统接受:

1 void try_start_program_here()
2 {
3     std::thread t( main ); //error
4 }

II 从对象/仿函数中创建

把仿函数依样搬进去:

1 struct say_hello
2 {
3     void operator()()const
4     {
5         std::cout << "Hello.\n";
6     }
7 };
1 std::thread t( say_hello() );
1   

把上边代码敲进去编译一下后,没有发现问题,链接后执行一下,没有看到 Hello. 打印出来, 这是因为编译器把这一行

1 std::thread t( say_hello() );

当成一个函数声明了(这个函数返回一个 std::thread 类型对象, 接受一个缺省的函数指针,这个函数指针返回一个 say_hello 类型对象,并且无参数)。

这是一个老问题了,从标准输入读取字符填充到一个 vector 的时候也曾有过这样的不便:

1 std::vector<std::string> vs( (std::istream_iterator<std::string>(cin)), std::istream_iterator<std::string>() );//parsed as an object
2 std::vector<std::string> vs( std::istream_iterator<std::string>(cin), std::istream_iterator<std::string>() );  //parsed as a function
1   

依样画葫芦,再套上一层括号搞定:

1 struct say_hello
2 {
3     void operator()()const
4     {
5         std::cout << "Hello.\n";
6     }
7 };
1 std::thread t( (say_hello()) );
1   

或者用时髦一点的 c++0x 引入的初始化语法:

1 struct say_hello
2 {
3     void operator()()const
4     {
5         std::cout << "Hello.\n";
6     }
7 };
8 std::thread t{ say_hello() };

直接复制一个对象也成:

1 struct say_hello
2 {
3     void operator()()const
4     {
5         std::cout << "Hello.\n";
6     }
7 };
8 say_hello sh;
9 std::thread t( sh );
1   

如果想消去对象复制的成本,那就传 reference :

1 struct say_hello
2 {
3     void operator()()const
4     {
5         std::cout << "Hello.\n";
6     }
7 };
8 say_hello sh;
9 std::thread t( std::ref(sh) );

这个 std::ref 也是 c++0x 引入的,需要多包含一个头文件:

1 #include <functional>

照着函数的处理方法,带参数的仿函数也这么干:

01 struct 
02 hello_from
03 {
04     void operator()()const
05     {
06         std::cout << "hello from default\n";
07     }   
08     void operator()( const char* const name )
09     {
10         std::cout << "hello from " << name << "\n";
11     }
12 };
13 std::thread t1{ hello_from() };
14 std::thread t2{ hello_from(), "http://www.cnblogs.com/feng_wang/" };

多个参数的仿函数情形依此类推。

需要参数进行初始化的对象也是如此:

01 struct say_something
02 {
03 private:
04     std::string name_;
05 public:
06     say_something( const std::string& name ) :
07     name(name_) {}
08     void operator()(const std::string& what) const    
09     {
10         std::cout << name << " said \"" << what << "\"\n";
11     }
12 };
13 std::thread t( say_something( "feng" ), "welcome." );

调用对象中的方法的时候则需要提供对象本身:

1 struct say_hello
2 {
3     void say( const std::string& what ) const
4     {
5         std::cout << what << "\n";
6     }
7 };
8 say_hello s;
9 std::thread t( &say_hello::say, &s, "hello" );

提供一个指针也可以:

1 struct say_hello
2 {
3     void say( const std::string& what ) const
4     {
5         std::cout << what << "\n";
6     }
7 };
8 say_hello* s = new say_hello;
9 std::thread t( &say_hello::say, s, "hello" );

不过为了防止这个线程执行过程中所传入的指针被另外一个线程意外释放,最好用智能指针 shared_ptr

1 struct say_hello
2 {
3     void say( const std::string& what ) const
4     {
5         std::cout << what << "\n";
6     }
7 };
8 std::shared_ptr<say_hello> s ( new say_hello );
9 std::thread t( &say_hello::say, s, "hello" );

shared_ptr 也是 c++0x 提供的,为了使用它,需要

1 #include <memory>

当然,如果线程调用对象中的一个 static 方法就不需要提供对象本身了(注意 static 的方法不能有 c-v 限定):

1 struct say_hello
2 {
3     static void say( const std::string& what )
4     {
5         std::cout << what << "\n";
6     }
7 };
8   
9 std::thread t( &say_hello::say, "hello" );

b 等待线程完结或者取消等待

这个很简单,单线程的时候只有 main 这一个线程,现在有了多线程之后,可以在创建新线程的线程中选择是否等待本线程创建的线程执行结束,还是直接返回:

等待完成:

1 //thread A
2 void f();
3 std::thread t( f );
4 t.join();

直接结束:

1 void f();
2 std::thread t( f );
3 t.detach();

上边说了这么多,给出一个完整的例子结束本篇:

01 #include <iostream>
02 #include <thread>
03   
04 void thanks()
05 {
06     std::cout << "Thank you for your reading.\n";
07 };
08   
09 int main()
10 {
11     std::thread t( thanks );
12     t.join();
13   
14     return 0;
15 }


Visual C++编程命名规则
任何时候都适用的20个C++技巧
C语言进阶
串口驱动分析
轻轻松松从C一路走到C++
C++编程思想
更多...   


C++并发处理+单元测试
C++程序开发
C++高级编程
C/C++开发
C++设计模式
C/C++单元测试


北京 嵌入式C高质量编程
中国航空 嵌入式C高质量编程
华为 C++高级编程
北京 C++高级编程
丹佛斯 C++高级编程
北大方正 C语言单元测试
罗克韦尔 C++单元测试
更多...