Gen_fsm行为实践与分析

1.简介

Gen_fsm是一个通用的有限状态机,它描述了这样的一组关系:

State(S) x Event(E) -> Actions(A),State(S‘)

这个关系意味着:如果在S状态下发生事件E,将执行动作A并返回状态S‘.对于一个FSM实现可以使用gen_fsm行为来实现,它提供了标准的接口函数和回调函数。并且,gen_fsm进程可以安装在supervisor监控树中。回调函数与导出函数的关系如下:

  1.  1 gen_fsm moduleCallbackmodule
     2 -----------------------------
     3 gen_fsm:start_link ----->Module:init/1
     4 gen_fsm:send_event ----->Module:StateName/2
     5 gen_fsm:send_all_state_event ----->Module:handle_event/3
     6 gen_fsm:sync_send_event ----->Module:StateName/3
     7 gen_fsm:sync_send_all_state_event ----->Module:handle_sync_event/4
     8 ------>Module:handle_info/3
     9 ------>Module:terminate/3
    10 ------>Module:code_change/4

如果回调函数失败或返回坏的值,gen_fsm将会终止。

gen_fsm处理系统消息记录记录在sys模块中(sys模块可以用来调试gen_fsm)。

注意:gen_fsm不会主动的捕获退出信号,必须在回调函数初始化时被指定。process_flag(trap_exit, true).

如果指定的gen_fsm不存在或给与的参数不正确,模块里的所有函数将失败。

如果回调函数返回‘hibernate‘,gen_fsm进程将进入hibernate状态。如果服务器长时间处于空闲状态这可能非常有用。然而应该非常小心的使用这个特征,因为它意味着至少有垃圾回收器,当调用一个忙碌的状态机时,你不能做你想做的事情(会因为垃圾回收而导致状态机停滞)。

2.函数

2.1导出函数

start_link(Module, Args, Options) -> Result
start_link(FsmName, Module, Args, Options) -> Result

FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}

Options = [Option]

Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}

Dbgs = [Dbg]

Dbg = trace | log | statistics

| {log_to_file,FileName} | {install,{Func,FuncState}}

SOpts = [SOpt]

SOpt - see erlang:spawn_opt/2,3,4,5

Result = {ok,Pid} | ignore | {error,Error}

Error = {already_started,Pid} | term()

用于创建一个gen_fsm进程,可以作为监控树的一部分。可以被监控树直接或间接的调用,将确保gen_fsm被链接到监控树。gen_fsm进程调用Module:init/1来初始化。为了确保同步的启动gen_fsm,start_link/3,4直到Module:init/1返回时才返回。

如果FsmName = {local,Name},gen_fsm在本地通过register/2注册为Name.如果FsmName = {global, GlobalName},gen_fsm在全局通过global:register_name/2注册为GlobalName.如果FsmNam = {via, Module, ViaName},gen_fsm通过Module注册为ViaName,同时回调模块Module将导出函数register_name/2, unregister_name/2, whereis_name/1和send/2,其原理同global,因此{via, Module, GlobalName}是一个有效的引用。

如果没有指定name,gen_fsm不被注册。

Args是一个任意的项式,用于作为Module:init/1的参数。

如果option是{timeout, Time}那么gen_fsm有Time毫秒进行初始化,否则,将返回{error, timeout}来终止。

如果option是{debug, Dbgs}那么Dbgs中相应的sys函数将被调用。详情见sys(3).

如果option是{spawn_opt, Sopts}那么通过指定的值列表来产生gen_fsm进程。详见erlang:spawn_opt

  1. link
  2. |{priority, priority_level()}
  3. |{min_heap_size, integer()>=0}
  4. |{min_bin_vheap_size, integer()>=0}
  5. |{fullsweep_after, integer()>=0}
如果gen_fsm被成功的创建和初始化,将返回{ok,Pid},如果已经存在指定FsName的进程,将返回{error,{alredy_started, Pid}}.

如果Module:init/1因为Reason失败,将返回{error,Reason}.如果Module:init/1返回{stop, Reason}或ignore,并且相应的返回{error,Reason}或ignore.

start(Module, Args, Options) -> Result
start(FsmName, Module, Args, Options) -> Result

FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}

Options = [Option]

Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}

Dbgs = [Dbg]

Dbg = trace | log | statistics

| {log_to_file,FileName} | {install,{Func,FuncState}}

SOpts = [term()]

Result = {ok,Pid} | ignore | {error,Error}

Error = {already_started,Pid} | term()

用于创建一个独立gen_fsm进程,并不是监控树的一部分。参数描述参见start_link/3,4.

send_event(FsmRef, Event) -> ok

FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()

向gen_fsm的FsmRef发送一个异步事件,并立即返回ok.gen_fsm将调用Module:StateName/2来处理事件,StateName为当前gen_fsm的状态。

FsmRef可能是:

  • Pid
  • Name,本地注册的gen_fsm
  • {Name,Node}另一个节点上本地注册gen_fsm
  • {global,GlobalName}全局注册的gen_fsm
  • {via,Module,ViaName}通过指定的进程注册的gen_fsm

Event是一个任意的项式,将被作为参数传递给Module:StateName/2处理。

send_all_state_event(FsmRef, Event) -> ok

FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()

向gen_fsm的FsmRef发送一个异步事件并立即返回ok.这个gen_fsm将调用Module:handle_event/3来处理这个事件。

参数描述参见send_event/2.

send_event和send_all_state_event的不同是处理事件的回调函数不同,该函数是在任何状态下都以同样的方式处理事件,只有一个handle_event子句来处理事件。

sync_send_event(FsmRef, Event) -> Reply
sync_send_event(FsmRef, Event, Timeout) -> Reply

FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()

Timeout = int()>0 | infinity

Reply = term()

向gen_fsm的FsmRef发送一个事件然后等待直到reply返回或发生超时,将调用Module:StateName/3来处理事件,StateName是gen_fsm当前的状态名。

参数描述参见send_event/2.

Timeout是一个等待reply返回大于0指定的毫秒数,或指定为infnity.默认是5000毫秒。如果指定时间内未返回reply函数调用失败。

返回值Reply是回调函数Module:StateName/3返回的。

sync_send_all_state_event(FsmRef, Event) -> Reply
sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply

FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()

Timeout = int()>0 | infinity

向gen_fsm的FsmRef发送一个事件然后等待reply的返回或超时。gen_fsm将调用Module:handle_sync_event/4来处理。

参数描述参见send_event/2和sync_send_event/3.

reply(Caller, Reply) -> true

Caller - see below

该函数用于通过gen_fsm向指定的客户端发送返回值,例如sync_send_event/2,3或sync_send_all_state/2,3当其回调函数Module:StateName/3或Module:handle_sync_event/4不能返回值时。

Caller是客户端的From,Reply是一个任意的项式,他将返回给sync_send_event/2,3或sync_send_all_state/2,3.

send_event_after(Time, Event) -> Ref

Time = integer()

Ref = reference()

用于在gen_fsm内部发送一个延迟事件,在Time时间后将触发。立即返回一个引用,它可以用cancel_timer/1来取消该延迟事件。

gen_fsm将调用Module:StateName/2处理该事件,StateName是当gen_fsm在延迟时间到时延迟事件被发送时的状态名字。

Event是任意类型的项式将作为参数传递给Module:StateName/2.

start_timer(Time, Msg) -> Ref

Time = integer()

Ref = reference()

在gen_fsm内部发送一个超时的事件,在Time事件时执行,并立刻返回他的引用,可以通过cancel_timer/1来取消该方法。

gen_fsm将调用Module:StateName/2处理该事件,StateName是发送该超时事件的状态。

Msg是任意类型项式的超时信息{timeout, Ref, Msg},将作为Module:StateName/2的参数信息。

cancel_timer(Ref) -> RemainingTime | false

Ref = reference()

RemainingTime = integer()

gen_fsm调用该函数来取消名称为Ref的内部定时器。

引用Ref是由send_event_after/2和start_timer/2返回。

如果定时器已经超时,但是并没用事件发送,他被作为超时事件被取消,因此该函数的返回不会有错误的计时器事件。

如果Ref指定的是活跃的事件计时器,将返回剩余的时间直到计时器终止前,否则返回false.

enter_loop(Module, Options, StateName, StateData)
enter_loop(Module, Options, StateName, StateData, FsmName)
enter_loop(Module, Options, StateName, StateData, Timeout)
enter_loop(Module, Options, StateName, StateData, FsmName, Timeout)

Options = [Option]

Option = {debug,Dbgs}

Dbgs = [Dbg]

Dbg = trace | log | statistics

| {log_to_file,FileName} | {install,{Func,FuncState}}

FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}

Timeout = int() | infinity

使一个存在的进程变成gen_fsm.没有返回,取而代之的是,调用进程将进入gen_fsm的接受循环成为一个gen_fsm进程。进程必须使用proc_lib来启动该函数.因此通过该函数进行初始化和名字注册。

当要进行一个比gen_fsm更要复杂的初始化过程时,这个函数非常有用。

Module, Options and FsmName与start_link中的意义一样。然而,如果FsmName被指定,在这个函数调用前,这个进程必须被相应地注册。

StateName,StateDate and Timeout的意义与Module:init/1一样。同时,回调模块Module不需要导出init/1方法。

失败情况:通过proc_lib启动函数不能启动该进程时;不能注册指定的FsmName时。

2.2回调函数

Module:init(Args) -> Result

Result = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout}

| {ok,StateName,StateData,hibernate}

| {stop,Reason} | ignore

Timeout = int()>0 | infinity

每当gen_fsm使用gen_fsm:start[_link]/3,4开始时,通过新进程调用该函数来初始化。

Args是启动函数提供的参数。

如果初始化成功,这个函数应该返回{ok, StateName, SateData[,Timeout | hibernate]},SateName是初始的状态名,StateData是初始的状态数据。

如果提供了一个整数的超时值,在Timeout时间内如果没有接受到事件或消息那么超时将发生。超时的表现是通过一个原子timeout被回调函数Modules:StateName/2处理。其默认值是infinity,表示会一直等待下去。

如果hibernate被指定,那么进程将进入hibernate状态等待下一个消息的到达。

如果在初始化期间发生了一些错误,函数应该返回{stop, Reason}或ignore.

Module:StateName(Event, StateData) -> Result

Event = timeout | term()

Result = {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,NewStateData}

Timeout = int()>0 | infinity

这是一个每个可能状态名的一个函数实例。每当gen_fsm接收到由gen_fsm:send_event/2发送过来的事件时,当前状态名StateName的函数实例将被调用来处理这个事件。同时他也处理超时事件。

Event要么是超时发生时的原子timeout,或send_event/2传递过来的。

如果该函数返回{next_state, NextStateName, NewStateData [, Timeout | hibernate]}时,gen_fsm将继续执行同时转变到新的状态NextStateName并更新数据NewStateDate.hibernate和Timeout的描述详见Module:init/1.

如果返回{stop, Reason, NewStateName},gen_fsm将调用Module:terminate(Reason, NewStateData)终止。

Module:handle_event(Event, StateName, StateData) -> Result

Result = {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,NewStateData}

Timeout = int()>0 | infinity

每当gen_fsm接收到由gen_fsm:send_all_state_event/2发送过来的事件时,这个函数将被调用来处理该事件。

参数描述以及返回值描述参见Module:StateName/2.

Module:StateName(Event, From, StateData) -> Result

From = {pid(),Tag}

Result = {reply,Reply,NextStateName,NewStateData}

| {reply,Reply,NextStateName,NewStateData,Timeout}

| {reply,Reply,NextStateName,NewStateData,hibernate}

| {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}

Timeout = int()>0 | infinity

Reason = normal | term()

这是一个每个可能状态名的一个函数实例。每当gen_fsm接收到由gen_fsm:sync_send_event/2发送过来的事件时,当前状态名StateName的函数实例将被调用来处理这个事件。

Event是由sync_send_event的Event参数提供。

From是一个元组{Pid, Tag},Pid是调用sync_send_event/2,3的进程的Pid,Tag是他的唯一标识。

当函数返回{reply, Reply, NextStateName, NewStateName [, Timeout | hibernate]}时,gen_fsm将继续执行同时转变到状态NextStateName,并跟新值到NewStateData.Timeout和hibernate的描述参见Module:init/1.

当函数返回{next_state, NextStateName, NewStateData [, Timeout | hibernate]}时,gen_fsm将继续执行,同时转变到状态NextStateName并更数据到NewStateName.同时必须现实的调用gen_fsm:reply/2来返回数据reply给From.

如果函数返回{stop, Reason, Reply, NewStateData}或{stop, Reason, NewStateNameData}(该情况必须明确的使用gen_fsm:reply/2返回reply)时,gen_fsm将调用Module:terminate(Reason NewStateName)终止。

Module:handle_sync_event(Event, From, StateName, StateData) -> Result

Result = {reply,Reply,NextStateName,NewStateData}

| {reply,Reply,NextStateName,NewStateData,Timeout}

| {reply,Reply,NextStateName,NewStateData,hibernate}

| {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}

Timeout = int()>0 | infinity

每当gen_fsm接受到由gen_fsm:sync_send_all_state_event/2,3发送过来的事件时,这个函数被调用来处理该事件。

参数详见Module:StateName/3描述。

Module:handle_info(Info, StateName, StateData) -> Result

Result = {next_state,NextStateName,NewStateData}

| {next_state,NextStateName,NewStateData,Timeout}

| {next_state,NextStateName,NewStateData,hibernate}

| {stop,Reason,NewStateData}

当gen_fsm接收到其他消息时(除出去同步或异步事件以及系统消息),该函数被调用来处理该消息。

其他参数以及返回值描述参见Module:StateName/2.

Module:terminate(Reason, StateName, StateData)

Reason = normal | shutdown | {shutdown,term()} | term()

这个函数在gen_fsm终止时被调用。它的作用与Module:init/1相对并可以做一些必要的清理。当他返回gen_fsm因为Reason终止的原因,返回值将被忽略。

如果Reason是term指定的停止原因,StateName就是当前状态,StateData就是当前状态数据。

如果Reason取决于gen_fsm为什么被终止。如果他是因为另一个回调函数返回了stop元组{stop,...},Reason将在那个元组里被指定。如果由于失败导致,Reason是一个错误原因。

如果gen_fsm是监控树的一部分,被他的监控树所终止,Reason = shutdown 要满足以下条件:

  • gen_fsm被设置成可捕获退出信号
  • 监控树的关闭策略是指定Timeout而不是brutal_kill
甚至如果gen_fsm并不是监控树的一部分,如果从其父进程接收到‘EXIT‘信号这个函数也会被调用,Reason就是‘EXIT‘信息。

否则,gen_fsm将立即终止。

注意:非normal, shutdown, or {shutdown,Term}的任何其他原因,如gen_fsm的终止是因为error,这些错误将由error_logger:format/2进行报告。

Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData}

OldVsn = Vsn | {down, Vsn}

关于代码的热更新,后续专题会继续介绍。

3.实践

3.1 启动一个gen_fsm
  1.  1 start_link(Code)->
     2 %%gen_fsm:start_link({local,?SERVER},?MODULE, lists:reverse(Code),[]).
     3 gen_fsm:start({local,?SERVER},?MODULE, lists:reverse(Code),[{timeout,1000}]).
     4 -spec(init(Args:: term())->
     5 {ok,StateName:: atom(),StateData::#state{}} |
     6 {ok,StateName:: atom(),StateData::#state{}, timeout() | hibernate} |
     7 {stop,Reason:: term()}| ignore).
     8 init(Code)->
     9 %%timer:sleep(2000),
    10 %%{stop,Code}.
    11 %%ignore.
    12 {ok, unlock,{[],Code}}.

当调用gen_fsm:start开启fsm服务器事,将回调Modules:init/1进行初始化,并初始化状态unlock,以及状态值{[],Code}.

3.2 发送一个事件
  1.  1 button(Digital)->
     2 gen_fsm:send_event(?SERVER,{button,Digital}).
     3 unlock({button,Digital},{SoFar,Code})->
     4 case[Digital|SoFar] of
     5 Code->
     6 io:format("Pass OK!~n"),
     7 do_unlock(),
     8 {next_state, open,{[],Code},3000};
     9 InCompletwhen length(InComplet)< length(Code)->
    10 io:format("Input:~p,InComplet~p,Code:~p~n",[Digital,[Digital|SoFar],Code]),
    11 {next_state, unlock,{InComplet,Code}};
    12 _Worng->
    13 io:format("ReInput Password!~n"),
    14 {next_state, unlock,{[],Code}}
    15 end.
    16 open(timeout,State)->
    17 do_lock(),
    18 timer:sleep(1000),
    19 %%{stop, normal,State}.
    20 {next_state, unlock,State}.

发送一个异步事件,然后当前状态对事件进行处理,根据一定的条件进行状态变更,返回{stop, Reason, State}将调用Module:terminate/2进行终止.

  1.  1 sync_button()->
     2 gen_fsm:sync_send_event(?SERVER,open).
     3 %%gen_fsm:sync_send_event(?SERVER,close,1000).
     4
     5 unlock(open,_From,State)->
     6 do_unlock(),
     7 io:format("~p~p~n",[_From,State]),
     8 gen_fsm:reply(_From,{ok,"Successfly!"}),
     9 %%gen_fsm:reply(_From,normal),{stop, normal,State}.
    10 %%{stop, normal, normal,State}.
    11 {next_state, close,State,1000}.
    12 %%Reply= ok,
    13 %%{reply,Reply, open,State,3000}.
    14 close(timeout ,State)->
    15 do_lock(),
    16 io:format("~p~p~n",["timeout",State]),
    17 {next_state, open,State,1000}.

发送一个同步事件,当前状态进行处理以后等待返回,返回{reply, Reply, StateName, State},Reply将返回给调用端。返回{next_state, State, State},那么必须在返回之前调用gen_fsm:reply/2显示的返回给调用端。

3.3 发送一个所有状态都能接受的事件
  1.  1 send(Data)->
     2 gen_fsm:send_all_state_event(?SERVER,{send,Data}).
     3 -spec(handle_event(Event:: term(),StateName:: atom(),
     4 StateData::#state{}) ->
     5 {next_state,NextStateName:: atom(),NewStateData::#state{}} |
     6 {next_state,NextStateName:: atom(),NewStateData::#state{},
     7 timeout()| hibernate}|
     8 {stop,Reason:: term(),NewStateData::#state{}}).
     9 handle_event({send,Data},StateName,State)->
    10 io:format("Send Data:~p,StateName:~p,State,~p~n",[Data,StateName,State]),
    11 {next_state,StateName,State}.

向所有的状态发送一个异步的事件,并由handle_event/3进行处理。

  1. 1 sync_send(Data)->
    2 Res= gen_fsm:sync_send_all_state_event(?SERVER,{send,Data}),
    3 io:format("~p~n",[Res]).
    4 handle_sync_event({send,Data},_From,StateName,State)->
    5 timer:sleep(2000),
    6 gen_fsm:reply(_From,{Data,StateName,State,_From}),
    7 {next_state, open,State,1000}.
    8 %%{reply,{Data,StateName,State,_From}, open,State,1000}.
    9 %%{reply,{Data,StateName,State,_From},StateName,State}.

向所有的状态发送一个同步事件,并由handle_sync_event/4进行处理,并向调用端返回Reply,如果返回{next_state, StateName, State}必须显示调用gen_fsm:reply/2向调用端返回。

3.4 开启一个定时器
  1.  1 unlock(open,_From,State)->
     2 do_unlock(),
     3 %%gen_fsm:send_event_after(2500,{button,48}),
     4 Ref= gen_fsm:start_timer(1500,"start_timer"),
     5 io:format("~p~p~n",[_From,State]),
     6 gen_fsm:reply(_From,{ok,"Successfly!"}),
     7 proc_lib:spawn(fun()->
     8 timer:sleep(2000),
     9 Time= gen_fsm:cancel_timer(Ref),
    10 io:format("RemainTime:~p~n",[Time])
    11 end),
    12 %%gen_fsm:reply(_From,normal),{stop, normal,State}.
    13 %%{stop, normal, normal,State}.
    14 {next_state, close,State,1000}.
    15 %%Reply= ok,
    16 %%{reply,Reply, open,State,3000}.

send_event_after/2表示在指定时间后发送事件,start_timer/2表示在指定事件后发送一个超时事件{timeout, Ref, Msg},但同时可以用cancel_timer/1来结束定时器。

3.5 将普通进程转变为gen_fsm进程
  1.  1 -spec(start_link()->{ok, pid()}| ignore |{error,Reason:: term()}).
     2 start_link()->
     3 io:format("start_link~n"),
     4 proc_lib:start_link(?MODULE, start_loop,[self()]).
     5 %%gen_fsm:start_link({local,?SERVER},?MODULE,[],[]).
     6 start_loop(Person)->
     7 io:format("start_loop~n"),
     8 proc_lib:init_ack(Person,self()),
     9 register(?MODULE,self()),
    10 gen_fsm:enter_loop(?MODULE,[], state_name,#state{}, {local, ?MODULE}).

通过gen_fsm:enter_loop将一个普通的进程转变为gen_fsm进程。同时不必导出Module:init/1回调函数。适用于比init:/1要更复杂的初始化的处理。

4.总结

gen_fsm实现了通用的有限状态机(FSM),对与在多种状态间的变更处理非常的有用,比如文本解析,模式匹配、游戏逻辑等等方面的处理都是它的强项,所以这个behaviour非常之重要,gen_fsm提供了简便的接口与回调函数来构建有限状态机,根据不同的返回参数在不同的状态间进行切换,也具备了同步或异步事件的处理。

博客地址:http://www.cnblogs.com/liuweiccy/p/4679825.html

源码地址:https://github.com/liuweiccy/test_sup_multi/tree/master/test_sup_gen_fsm

优秀的代码是艺术品,它需要精雕细琢!

来自为知笔记(Wiz)

时间: 2024-10-29 17:16:17

Gen_fsm行为实践与分析的相关文章

C++ Primer 学习笔记_29_STL实践与分析(3) --操作步骤集装箱(下一个)

STL实践与分析 --顺序容器的操作(下) 六.訪问元素 假设容器非空,那么容器类型的front和back成员将返回容器的第一个和最后一个元素的引用. [与begin和end的对照:] 1)begin和end返回容器类型的迭代器,而不是引用: 2)end返回容器最后一个元素的下一个位置的迭代器,而back返回容器的最后一个元素的引用! /* *必须保证该list容器非空! *假设容器为空,则if语句内的全部操作都是没有定义的! */ if (!iList.empty()) { list<int>

C++ Primer 学习笔记_35_STL实践与分析(9)--map种类(在)

STL实践与分析 --map类型(上) 引: map是键-值对的集合. map类型通常能够理解为关联数组:能够通过使用键作为下标来获取一个值,正如内置数组类型一样:而关联的本质在于元素的值与某个特定的键相关联,而并不是通过元素在容器中的位置来获取. 一.map对象的定义 1.定义map对象时,必须分别指明键和值的类型: map<string,int> wordCnt; map的构造函数 map<K,V>m; 创建一个名为m的空对象,其键和值的类型分别为K和V map<K,V&

C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】

STL实践与分析 --初窥算法[下] 一.写容器元素的算法 一些算法写入元素值.在使用这些算法写元素时一定要当心.必须确保算法所写的序列至少足以存储要写入的元素. 1.写入输入序列的元素 写入到输入序列的算法本质上是安全的--仅仅会写入与指定输入范围数量同样的元素. 写入到输入序列的一个简单算法是fill函数: fill(iVec.begin(),iVec.end(),10); fill(iVec.begin(),iVec.begin()+iVec.size()/2,0); fill带有一对迭代

C++ Primer 学习笔记_45_STL实践与分析(19)--泛型算法的结构

STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用的迭代器类型.比方,假设形參必须为随机訪问迭代器则可提供vector或 deque类型的迭代器,或者提供指向数组的指针.而其它容器的迭代器不能用在这类算法上. C++还提供了另外两种算法模式:一种模式由算法所带的形參定义;还有一种模式则通过两种函数命名和重载的规范定义. 一.算法的形參模式 大多数的

C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法

STL实践与分析 --容器特有的算法 与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作.当中非常大的一个原因就是list容器不是依照内存中的顺序进行布局的,不支持随即訪问,这样,在list容器上就不能使用随即訪问迭代器的算法,如sort等:还有其它的一些算法如:merge.remove.reverse和unique,尽管能够用在list上,但却付出了高昂的性能代价.因此标准库结合list的内部结构,编写出了更快算法: list容器特有的操作

C++ Primer 学习笔记_45_STL实践与分析(19)--建筑常规算法

STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用的迭代器类型. 比方,假设形參必须为随机訪问迭代器则可提供vector或 deque类型的迭代器,或者提供指向数组的指针. 而其它容器的迭代器不能用在这类算法上. C++还提供了另外两种算法模式:一种模式由算法所带的形參定义;还有一种模式则通过两种函数命名和重载的规范定义. 一.算法的形參模式 大多

C++ Primer 学习笔记_44_STL实践与分析(18)--再谈迭代器【下】

STL实践与分析 --再谈迭代器[下] 三.反向迭代器[续:习题] //P355 习题11.19 int main() { vector<int> iVec; for (vector<int>::size_type index = 0; index != 10; ++index) { iVec.push_back(index); } for (vector<int>::reverse_iterator r_iter = iVec.rbegin(); r_iter !=

C++ Primer 学习笔记_43_STL实践与分析(17)--再谈迭代器【中】

STL实践与分析 --再谈迭代器[中] 二.iostream迭代[续] 3.ostream_iterator对象和ostream_iterator对象的使用 能够使用ostream_iterator对象将一个值序列写入流中,其操作过程与使用迭代器将一组值逐个赋值给容器中的元素同样: ostream_iterator<string> out_iter(cout,"\n"); istream_iterator<string> in_iter(cin),eof; wh

C++ Primer 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】

STL实践与分析 --概述.初窥算法[上] 标准库容器定义的操作很少.并没有给容器加入大量的功能函数.而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是"泛型"的.可作用在不同类型的容器和不同类型的元素上! 所谓泛型算法:一是由于它们实现共同的操作,所以称之为"算法";而"泛型"指的是它们可以操作在多种容器类型上--不但可作用于vector或list这些标准库类型,还可用在内置数组类型.甚至其它类型的序列上,仅仅要自己定义的容器类型仅仅要