找回密码
 立即注册
收起左侧

C++老鸟日记012 变量作用域

2
回复
4862
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2018-9-5 17:19:29 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 baizy77 于 2018-10-1 20:47 编辑

版权声明
---------------------------------------------------------------------------------------------------------------------
该文章原创于Qter开源社区(www.qter.org
作者: 女儿叫老白 (白振勇)
转载请注明出处!
---------------------------------------------------------------------------------------------------------------------
本套课程属于:《C++跨平台开发干货》系列课程。
-----------------------------------------------------------------------------

引言
-----------------------------------------------------------------------------
     就像我们在地球上生活一样,理开地球我们可能难以生存,变量也一样,也有自己的生存期和作用域,我们今天来讨论一下变量的作用域。

正文
-----------------------------------------------------------------------------(3.5, 3.6)。
变量的作用域存在于离它最近的一对括号{}。C++中,我们可以在作用域的任意位置定义变量,比如在for循环中,但是一定要注意,变量的命名务必有含义,避免采用int i之类的定义。因为在循环体中我们也可能会用int i。这样就极有可能同循环体之外的int i产生混淆,导致代码运行时出现我们期望之外的结果。
       全局变量是可以在一处定义,然后在其他cpp中也可使用的变量。全局变量定义于函数体之外,且不受作用域的影响,在程序的整个生命周期内都有效。使用extern声明一个变量是全局变量。
       // a.cpp
       int g_ConfigCount = 0;

       // b.cpp
       extern int g_ConfigCount;
       如果我们在函数体之外定义一个变量x,但是又不希望在其他cpp中看到x,那么就可以用静态变量:
       // c.cpp
       static double s_Zero = 0.0001f;
       // d.cpp
       extern double s_Zero; // error! 编译错误

       在函数体内部定义的static变量,表示该变量在内存中常驻且只初始化一次,变量生存期不受函数堆栈的影响。既然只初始化一次,那么在变量定义时就必须初始化。
       // e.cpp
       int parseFile(const string&strFileName)
{
       static ints_successCount = 0;
       ……
       if (…) {
              s_successCount++;
}      
}
但是全局变量或者静态变量的初始化是跟编译器相关的,不受编程人员的控制,有时候它的初始化可能出现意想不到的结果。我就碰到过文件作用域内的静态变量初始化两次的情况,这是有问题的,会导致程序出现不可预知的结果。因此如果使用 static定义文件作用域的静态变量,请使用全局锁进行保护(不能用类的成员锁),比如:
       // f.cpp
       CMutex g_mtx;      // 全局锁,不能用类的成员锁。

       CMyClass& CMyClass::getInstance() {
              g_mtx.lock();
              static CMyClassobj;
              return obj;
              g_mtx.unlock();
}
--------------------------------总结  --------------------------------------
1. 变量的作用域存在于离它最近的一对括号{}。
2. 变量命名要规范,避免使用i、j、k等名称。循环体内外避免变量重名。
3. static变量可以用在文件作用域内,仅在某个文件内可见。
4. 全局变量初始化过程可能不可预测。
回复

使用道具 举报

累计签到:50 天
连续签到:1 天
2018-9-6 23:05:03 显示全部楼层
大神,  锁中锁好不好。   像这样的      
                g_mtx.lock();
              staticCMyClass obj;
              returnobj;

                  m_mtx.lock();

                   m_data();
                  m_mtx.unlock();
              g_mtx.unlock();

像这样用锁会出现毛病么?
回复 支持 反对

使用道具 举报

累计签到:41 天
连续签到:1 天
2018-9-7 09:07:01 显示全部楼层
本帖最后由 baizy77 于 2018-9-8 22:23 编辑

您的代码,我没有看明白,第三行已经return了?如果第三行执行return,则会导致 g_mtx没有解锁。

另外,双重锁的设计极易导致死锁的发生。比如:
    线程A(或接口A):
              mtx_a.lock();  // a锁已被锁
                   do something;
              mtx_b.lock(); // 等着锁住b
                   do something;
              mtx_b.unlock();
              mtx_a.unlock();
   线程B(或接口B):
              mtx_b.lock();  // b锁已被锁
                   do something;
              mtx_a.lock();  // 等着锁住a
                   do something;
              mtx_a.unlock();
              mtx_b.unlock();

    上面的设计,将极易导致mtx_a和mtx_b相互发生死锁。

   建议在访问数据时,先进入一个锁,获取数据返回并解锁后,再进另外一个锁。
   如果必须按照顺序访问两个数据或执行两种操作,建议再另外建立一个公共锁,m_mtxPublic.
按照如下方式编码:
-------------------------------------
线程A(或接口A):
m_mtxPublic.lock()
    {
        锁1.lock(),访问数据1,
        锁1.unlock(),
    }

    {
        锁2.lock(),访问数据2
        锁2.unlock(),
    }
m_mtxPublic.unlock()

线程B(或接口B):
m_mtxPublic.lock()
    {
        锁2.lock(),访问数据2,
        锁2.unlock(),
    }

    {
        锁1.lock(),访问数据1
        锁1.unlock(),
    }
m_mtxPublic.unlock()

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了