1 ---- auto
auto : 类型自动推导 ( type deduction )
考虑下边这一行程序
由于 auto 的自动类型推导,a1 自动被编译器识别为 int 类型。更一般的使用方式是这样的:
也就是说,有了auto之后,变量类型可以由编译器自动从初始化的表达式中识别出来:
对模板也有用:
1 |
template < typename
T1,
typename T2>
|
2 |
double
sum( T1& t1, T2&
t2 ) |
这看起来有些无聊而且降低了程序的可读性,不过在类型相当复杂的时候非常有用 :
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 ) |
而且,得益于 c++0x 新型的 for 循环控制,更方便的写法是:
当然,如果想修改 m 元素的内容,就要用引用:
更进一步
auto 可以与 static,const,volatile,* 和 & 等一起用:
再如:
碰到引用时跟指针稍微有些区别:
上边变量 i1 的类型是 int ,不是 int& 。
auto 在涉及到虚拟继承时候类型推导也没有什么问题:
03 |
virtual
void operator()()
const |
11 |
virtual
void operator()()
const |
输出都是 d()() 。
auto 直接初始化写法是非常容易上手的:
包括指针初始化:
上边三句执行动作完全一样。
有多个变量要一起 auto 也行:
只要不试图调戏编译器就可以:
2 |
auto
i = 1, j = 1.0; //error |
更多
一个比较无聊的用法可以是这样的:
变量 i 被定义为 int 类型,不需要初始化参量。
碰到数组时候稍微尴尬点:
2 |
auto
v1[3] = {1, 2, 3}; //error
|
3 |
auto
v1[] = {1, 2, 3}; //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 |
void
hello_from( const
char *
str const )
|
3 |
std::cout
<< "hello
from " <<
str << "\n" ;
|
5 |
std:: thread
t( hello_from, "thread
t" ); |
多个参数的函数也是如此:
1 |
void
max( const
long m,
const long
n ) |
3 |
std::cout
<< "max("
<< m << ",
" << n <<
")="
<< (m>n?m:n) <<
"\n" ;
|
5 |
std:: thread
t( max, 13, 31 ); |
可以依此类推到3个、4个……参数的函数情形。
只要不把 main 函数也弄进去,编译器统统接受:
1 |
void
try_start_program_here()
|
3 |
std:: thread
t( main );
//error |
II 从对象/仿函数中创建
把仿函数依样搬进去:
5 |
std::cout
<< "Hello.\n" ;
|
1 |
std:: thread
t( say_hello() ); |
把上边代码敲进去编译一下后,没有发现问题,链接后执行一下,没有看到 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 |
依样画葫芦,再套上一层括号搞定:
5 |
std::cout
<< "Hello.\n" ;
|
1 |
std:: thread
t( (say_hello()) ); |
或者用时髦一点的 c++0x 引入的初始化语法:
5 |
std::cout
<< "Hello.\n" ;
|
8 |
std:: thread
t{ say_hello() }; |
直接复制一个对象也成:
5 |
std::cout
<< "Hello.\n" ;
|
如果想消去对象复制的成本,那就传 reference :
5 |
std::cout
<< "Hello.\n" ;
|
9 |
std:: thread
t( std::ref(sh) ); |
这个 std::ref 也是 c++0x 引入的,需要多包含一个头文件:
照着函数的处理方法,带参数的仿函数也这么干:
04 |
void
operator()() const |
06 |
std::cout
<< "hello
from default\n" ;
|
08 |
void
operator()( const
char *
const name
) |
10 |
std::cout
<< "hello
from " <<
name << "\n" ;
|
13 |
std:: thread
t1{ hello_from() }; |
多个参数的仿函数情形依此类推。
需要参数进行初始化的对象也是如此:
06 |
say_something(
const std::string&
name ) : |
08 |
void
operator()( const
std::string& what)
const |
10 |
std::cout
<< name << "
said \"" <<
what << "\"\n" ;
|
13 |
std:: thread
t( say_something(
"feng"
), "welcome."
); |
调用对象中的方法的时候则需要提供对象本身:
3 |
void
say( const
std::string& what )
const |
5 |
std::cout
<< what << "\n" ;
|
9 |
std:: thread
t( &say_hello::say, &s,
"hello"
); |
提供一个指针也可以:
3 |
void
say( const
std::string& what )
const |
5 |
std::cout
<< what << "\n" ;
|
8 |
say_hello*
s = new say_hello;
|
9 |
std:: thread
t( &say_hello::say, s,
"hello"
); |
不过为了防止这个线程执行过程中所传入的指针被另外一个线程意外释放,最好用智能指针 shared_ptr
3 |
void
say( const
std::string& what )
const |
5 |
std::cout
<< what << "\n" ;
|
8 |
std::shared_ptr<say_hello>
s ( new say_hello
); |
9 |
std:: thread
t( &say_hello::say, s,
"hello"
); |
shared_ptr 也是 c++0x 提供的,为了使用它,需要
当然,如果线程调用对象中的一个 static 方法就不需要提供对象本身了(注意 static 的方法不能有
c-v 限定):
3 |
static
void say(
const std::string&
what ) |
5 |
std::cout
<< what << "\n" ;
|
9 |
std:: thread
t( &say_hello::say,
"hello"
); |
b 等待线程完结或者取消等待
这个很简单,单线程的时候只有 main 这一个线程,现在有了多线程之后,可以在创建新线程的线程中选择是否等待本线程创建的线程执行结束,还是直接返回:
等待完成:
直接结束:
上边说了这么多,给出一个完整的例子结束本篇:
06 |
std::cout
<< "Thank
you for your reading.\n" ;
|
11 |
std:: thread
t( thanks ); |
|