ZRY(周大神)代码 里的一些解释

一、 

C ++ 函数后面加throw()的作用

1、throw一个函数体,形式如下:
void fun (); // 能抛出任何类型的异常
void fun () throw(except1,except2,except3)       // 后面括号里面是一个异常参数表,本例中只能抛出这3中异常
void fun () throw()   // 参数表为空,不能抛出异常

问题b:假设fun()中抛出了一个不在“异常参数表”中的异常,会怎么样?

答:调用set_terminate()中设定的终止函数。然而,这只是表面现象,实际上是调用默认的unexpected()函数,然而这个默认的unexpected()调用了set_terminate()中设定的终止函数。可以用set_unexpected()来设置 unexpected,就像set_terminate()一样的用法,但是在设定了新的“unexpected()”之后,就不会再调用 set_terminater中设定的终止函数了。

这个语法是很有用的,因为在用别人的代码时,不知道哪个地方会调用什么函数又会抛出什么异常,用一个异常参数表在申明时限制一下,很实用。


二、

inline函数和一般的函数有什么不同
比如 
int g(int x) 
{ 
return x + x; 
} 

int f() 
{ 
return g(); 
} 

这样f会调用g,然后g返回x + x给f,然后f继续把那个值返回给调用者。 

如果g是inline的话。f会被直接编译成。 

int f() 
{ 
return x + x; 
} 

相当于把g执行的操作直接融合到f里。这样减少了调用g消耗的时间,但同时也增大了f的尺寸。 

这就是inline函数,也就是所谓的内联函数
三、 #pragma once
只要在头文件的最开始加入这条杂注,就能够保证头文件只被编译一次。
#pragma once是编译器相关的,有的编译器支持,有的编译器不支持,具体情况请查看编译器API文档,不过现在大部分编译器都有这个杂注了。
#ifndef,#define,#endif是C/C++语言中的宏定义,通过宏定义避免文件多次编译。所以在所有支持C++语言的编译器上都是有效的,如果写的程序要跨平台,最好使用这种方式。

四、1. mutex对象类

mutex类主要有两种:独占式与共享式的互斥量。
独占式互斥量:
mutex: 独占式的互斥量,是最简单最常用的一种互斥量类型
try_mutex: 它是mutex的同义词,为了与兼容以前的版本而提供
timed_mutex: 它也是独占式的互斥量,但提供超时锁定功能
▲ 递归式互斥量:
recursive_mutex: 递归式互斥量,可以多次锁定,相应地也要多次解锁
recursive_try_mutex: 它是recursive_mutex 的同义词,为了与兼容以前的版本而提供
recursive_timed_mutex: 它也是递归式互斥量,基本功能同recursive_mutex, 但提供超时锁定功能
▲ 共享式互斥量:
shared_mutex: multiple-reader/single-writer 型的共享互斥量(又称读写锁)。
其中mutex有lock和unlock方法,shared_mutex除了提供lock和unlock方法外,还有shared_lock和shared_unlock方法。

2. lock模板类

▲ 独占锁:
boost::unique_lock<T>,其中T可以mutex中的任意一种。
  如果T为mutex,那么boost::unique_lock<boost::mutex>,构造与析构时则分别自动调用lock和unlock方法。
  如果T为shared_mutex,那么boost::unique_lock<boost::shared_mutex>,构造与析构时则分别调用shared_mutex的shared_lock和shared_unlock方法。
注意:scoped_lock也是独占锁,其源代码中定义如下;
  typedef unique_lock<mutex> scoped_lock;
  typedef unique_lock<timed_mutex> scoped_timed_lock;
▲ 共享锁:
boost::shared_lock<T>,其中的T只能是shared_mutex类。
当然还有其他一些锁:lock_guard, upgrade_lock等。

除了thread,boost::thread另一个重要组成部分是mutex,以及工作在mutex上的boost::mutex::scoped_lock、condition和barrier,这些都是为实现线程同步提供的。
mutex
boost提供的mutex有6种:
boost::mutex
boost::try_mutex
boost::timed_mutex
boost::recursive_mutex
boost::recursive_try_mutex
boost::recursive_timed_mutex
下面仅对boost::mutex进行分析。
mutex类是一个CriticalSection(临界区)封装类,它在构造函数中新建一个临界区并InitializeCriticalSection,然后用一个成员变量
void
* m_mutex;
来保存该临界区结构。
除此之外,mutex还提供了do_lock、do_unlock等方法,这些方法分别调用EnterCriticalSection、 LeaveCriticalSection来修改成员变量m_mutex(CRITICAL_SECTION结构指针)的状态,但这些方法都是private的,以防止我们直接对mutex进行锁操作,所有的锁操作都必须通过mutex的友元类detail::thread::lock_ops<mutex>来完成,比较有意思的是,lock_ops的所有方法:lock、unlock、trylock等都是static

当我们不指定initially_locked参数构造一个scoped_lock对象时,scoped_lock会自动对所绑定的mutex加锁,而析构函数会检查是否加锁,若已加锁,则解锁;当然,有些情况下,我们可能不需要构造时自动加锁,这样就需要自己调用lock方法。后面的condition、barrier也会调用scoped_lock的lock、unlock方法来实现部分方法。
正因为scoped_lock具有可在构造时加锁,析构时解锁的特性,我们经常会使用局部变量来实现对mutex的独占访问。

在使用 scoped_lock时,我们有时候需要使用全局锁(定义一个全局mutex,当需要独占访问全局资源时,以该全局mutex为参数构造一个 scoped_lock对象即可。全局mutex可以是全局变量,也可以是类的静态方法等),有时候则需要使用对象锁(将mutex定义成类的成员变量),应该根据需要进行合理选择。

六、boost线程库。在创建线程时遇到了几种线程创建方式现总结如下:

最近在做一个消息中间件里面涉及到多线程编程,由于跨平台的原因我采用了boost线程库。在创建线程时遇到了几种线程创建方式现总结如下:  
  首先看看boost::thread的构造函数吧,boost::thread有两个构造函数: 
(1)thread():构造一个表示当前执行线程的线程对象; 
(2)explicit thread(const boost::function0<void>& threadfunc): 
    boost::function0<void>可以简单看为:一个无返回(返回void),无参数的函数。这里的函数也可以是类重载operator()构成的函数;该构造函数传入的是函数对象而并非是函数指针,这样一个具有一般函数特性的类也能作为参数传入,在下面有例子。 
第一种方式:最简单方法 
#include <boost/thread/thread.hpp> 
#include <iostream> 
  
void hello() 
{ 
        std::cout << 
        "Hello world, I''m a thread!" 
        << std::endl; 
} 
  
int main(int argc, char* argv[]) 
{ 
        boost::thread thrd(&hello); 
        thrd.join(); //<span style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 25.2px;">当 a thread 调用Join方法的时候,MainThread 就被停止执行,直到 a thread 线程执行完毕。</span>
        return 0; 
} 

最后,我们可以这样翻译MSDN:当一个 thread 调用Join方法的时候,MainThread 就被停止执行,直到一个 thread 线程执行完毕。

第二种方式:复杂类型对象作为参数来创建线程: 
#include <boost/thread/thread.hpp> 
#include <boost/thread/mutex.hpp> 
#include <iostream> 
  
boost::mutex io_mutex; 
  
struct count 
{ 
        count(int id) : id(id) { } 
        
        void operator()() 
        { 
                for (int i = 0; i < 10; ++i) 
                { 
                        boost::mutex::scoped_lock 
                        lock(io_mutex); 
                        std::cout << id << ": " 
                        << i << std::endl; 
                } 
        } 
        
        int id; 
}; 
  
int main(int argc, char* argv[]) 
{ 
        boost::thread thrd1(count(1)); 
        boost::thread thrd2(count(2)); 
        thrd1.join(); 
        thrd2.join(); 
        return 0; 
} 

第三种方式:在类内部创建线程; 
(1)类内部静态方法启动线程 
#include <boost/thread/thread.hpp>
#include <iostream> 
class HelloWorld
{
public:
 static void hello()
 {
      std::cout <<
      "Hello world, I''m a thread!"
      << std::endl;
 }
 static void start()
 {
  
  boost::thread thrd( hello );
  thrd.join();
 }
 
}; 
int main(int argc, char* argv[])
{
 HelloWorld::start();
 
 return 0;
} 

在这里start()和hello()方法都必须是static方法。 

如果线程需要绑定的函数有参数则需要使用boost::bind。
比如想使用 boost::thread创建一个线程来执行函数:void f(int i),如果这样写:boost::thread thrd(f)是不对的,因为thread构造函数声明接受的是一个没有参数且返回类型为void的型别,而且不提供参数i的值f也无法运行,这时就可以写:boost::thread thrd(boost::bind(f,1))。
涉及到有参函数的绑定问题基本上都是boost::thread、boost::function、boost::bind结合起来使用


七: vc2005开发ActiveX+event步骤

由于vc2005在开发activex中有bug,(向导不能生成event),在使用时不能自己封装activex控件类,下面把开发过程总结如下: 生成event: 

1、在*.idl文件的dispinterface _DXXEvents 的methods: 下添加 //XX:activex控件名   

     [id(intValue)] void EventName();//intValue整数值,此event的ID

2、在XXCtrl.h文件的enum下 添加 eventidEventName = intValue

3、在XXCtrl.h文件控件类下添加函数  
     void EventName()
    {   //你想添加的代码  
       //...    FireEvent(eventidEventName, EVENT_PARAM(VTS_NONE));
    }

 4、在XXCtrl.cpp文件的BEGIN_EVENT_MAP和END_EVENT_MAP间添加:
 
    EVENT_CUSTOM_ID("EventName", eventidEventName, EventName, VTS_NONE)
   
经过以上步骤就添加了一个没有参数的Event 如果有参数比如两个参数 BSTR strvalue, LONG lValue 那么相应的添加如下:

    1)、   [id(intValue)] void EventNam(BSTR strvalue, LONG lValue);

    2)、   void EventName(LPCTSTR strvalue, LONG lValue) 
          {     
              //...    
             FireEvent(eventidEventName, EVENT_PARAM(VTS_BSTR VTS_I4), strvalue, lValue); 
          }
    3)、   EVENT_CUSTOM_ID("EventName", eventidEventName, EventName, VTS_BSTR VTS_I4)


八、 MFC中 VTS_I4 VTS_CY VTS_BSTR是什么意思

        是ocx自动生成的一个数据类型

九、

函数模板的任何实例的remove_if匹配参数列表

  ---我试图从一个字符串中删除空格
头文件:#include <algorithm>
1、例如:
string line="hello world 111 2222";
line.erase(remove_if(line.begin(),line.end(),isspace),line.end());
cout<<line<<endl;//输出:helloworld1112222


或者写成这样:
       
        string line="hello world 111 2222";
auto iter = remove_if(line.begin(),line.end(),isspace);
line.erase(iter,line.end());
       cout<<line<<endl;//输出:helloworld1112222

2、如果string字符串里,含有中文字符,用isspace 就会出错,如:

string line="hello world 111 2222 中文";
auto iter = remove_if(line.begin(),line.end(),isspace);//在这里就会出错
line.erase(iter,line.end());
cout<<line<<endl;  


3、如果含有中文字符,如何处理:下面代码的功能: 一个去除一个xml字符串城的所有空格,并保存成xml文件

bool isSpace(char c )
{
return c==' ';
}
string trimAllspace(string value)
{
auto iter = remove_if(value.begin(),value.end(),isSpace);
value.erase(iter,value.end());
return move(value);
}

void saveXml2File(string &xmlData,string &filename)
{
ofstream outfile(filename);
outfile<<trimAllspace(xmlData);
outfile.close();
}

十、 C++中的unordered_map,以及与STL中的map的比较

unordered_map是C++ Boost库中的内容,这里的unordered翻译成“无序”。

头文件:#include <unordered_map>

但它并不是完全的“无序”的概念,而是散列式的存储方式

unordered库提供了两个散列映射类,unordered_map和unordered_multimap。

它们的接口、用法与STL里的标准关联容器map和multimap相同,但是内部实现不同。

它们用散列表代替了二叉树的实现,模板参数多了散列计算函数,比较谓词使用equal_to<>。

看到这里,我们就应该明白,比起map/multimap,unordered_map和unordered_mutimap在查找元素的时候,速度不是一般的快。

它们的查找速率是常数级的,而map/multimap是基于二叉树实现的,所以查找是O(log n)的复杂度。下面,来看看unordered_map的声明吧:

template < class Key,                                     //unordered_map::key_type

          class T,                                                 //unordered_map::mapped_type

           class Hash = hash<Key>,                      // unordered_map::hasher

           class Pred =equal_to<Key>,                   //unordered_map::key_equal

           class Alloc = allocator<pair<const Key,T> >     // unordered_map::allocator_type

           > class uno


unordered_map属于关联式容器,采用std::pair保存key-value形式的数据。用法与map一致。特别的是,STL中的map因为是有序的二叉树存储,所以对key值需要有大小的判断,当使用内置类型时,无需重载operator < ;但是用用户自定义类型的话,就需要重载啦! unoredered_map全程使用不需要比较元素的key值的大小,但是,对于元素的==要有判断,又因为需要使用hash映射,所以,对于非内部类型,需要程序员为其定义这二者的内容,对于内部类型,就不需要了。


unordered库使用“桶”来存储元素,散列值相同的被存储在一个桶里。当散列容器中有大量数据时,同一个桶里的数据也会增多,造成访问冲突,降低性能。为了提高散列容器的性能,unordered库会在插入元素是自动增加桶的数量,不需要用户指定。但是,用户也可以在构造函数或者rehash()函数中,指定最小的桶的数量。


十一、C++ std::pair 与 std::make_pair

std::pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。例如std::pair<int,float> 或者 std::pair<double,double>等。pair实质上是一个结构体,其主要的两个成员变量是first和second,这两个变量可以直接使用。初始化一个pair可以使用构造函数,也可以使用std::make_pair函数,make_pair函数的定义如下:

一般make_pair都使用在需要pair做参数的位置,可以直接调用make_pair生成pair对象。 另一个使用的方面就是pair可以接受隐式的类型转换,这样可以获得更高的灵活度。但是这样会出现如下问题:例如有如下两个定义: 

std::pair<intfloat>(11.1);

std::make_pair(
11.1);


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值