精华内容
下载资源
问答
  • C++当中常常需要一个全局唯一的对象... 既然全局变量是可能有害的,那么,我们我们把它隐藏一下,放到某个类当中去,作为类的静态数据成员。这看上去不错,我也这么认为。当我们只是简单的需要一个全局对象时,这很
    C++当中常常需要一个全局唯一的对象实例,这时候,我们就会想到单件模式。如何实现这一模式?全局变量当然是一个简单可行的方法,然而,这太丑陋。嗯,其实,丑陋倒也罢了,最严重的是它将引诱程序员滥用全局变量,这将导致维护的灾难。 
    
      
      既然全局变量是可能有害的,那么,我们我们把它隐藏一下,放到某个类当中去,作为类的静态数据成员。这看上去不错,我也这么认为。当我们只是简单的需要一个全局对象时,这很好,而且足够简单。不过,天空中尚有一朵小小的乌云,让我们来看一看它是什么。
      
      静态成员变量的初始化,和全局对象一样,实际上实在main函数进入后,我们写下的一行代码之前被执行的。而且,我们知道那个著名的初始化顺序是不可靠的问题(跨编译单元)。当我的全局对象是一个复杂对象――这很常见,比如一个环境管理器――它甚至还需要复杂的装配过程,我们需要考虑:构建这个单件的时候,其对象都准备好了吗?如果我们不能确定,那么一个常见的措施是延迟单件对象的构造――把它延迟到全局对象初始化结束以后怎么样?这好像很容易实现:
      
      SomeClass * SomeClass ::instance(){
      static SomeClass inst;
      return &inst;
      }
      
      不错吧?它不但可以延迟到全局对象初始化之后,甚至可以延迟到有人需要它的时候,才被构造出来,随需应变,呵呵,是不是很帅?嗯,还有一点小问题,不仅存在对象初始
    展开全文
  • C++静态成员变量初始化和赋值

    万次阅读 2019-03-07 14:29:57
    使用静态成员变量实现个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。 static成员的所有者是类本身和对象,但是个对象拥有一样的静态成员。从而在定义对象时不能通过构造函数对其进行...

    1.背景

    有这样一套会话机制,CSession为会话对象,CSessionManager为会话管理类,在CSession会话需要销毁时,CSession主动发送消息给CSessionManager销毁session。同时CSession是一个基类,子类通过继承CSession实现不同的session处理。

    实现主要考虑三个方面(创建、处理、销毁):

    1. 通过不同的server创建不同的session会话;
    2. 子类通过CSession提供的虚函数接口实现多态;
    3. 通过消息对象指针发送消息给CSessionManager销毁session;

    问题卡在session的销毁:

    CSessionManager通过消息队列模板类创建消息对象,保存消息对象指针信息,并且有一个线程专门接收该对象发送的消息。那么CSession会话类也需要知道和保存消息对象指针。

    先前有类似情况,消息对象指针是通过构造传参保存下来的。但现在CSession作为一个基类(要被继承),显然通过构造传参是非常不合理的,并且我希望CSession只保存一份消息对象指针(static成员变量),提供唯一 一个发送消息的接口给子类。

    大致代码如下:

    typedef struct
    {
    	int connfd;
    	int keepfd;		/*是否保留fd:1-是,其他-否*/
    }SocketSessionExp;
    
    //session会话基类(HttpSession、RtspSession继承该类)
    class CSession
    {
    	friend class CSessionManager;
    	public:
    		CSession();
    		virtual ~CSession();
    	protected:
    		static void sendMessage(SocketSessionExp &expMessage);//希望CSession对象和子类能通过这个唯一接口发送消息给CSessionManager销毁该CSession会话
    	private:
    		static TMessageQue<SocketSessionExp> *m_exception_msq;//TMessageQue为消息队列模板类
    }
    
    //会话管理类
    class CSessionManager
    {
    public:
    	static CSessionManager* instance();		//单健类
    private:
    	CSessionManager();
    	{
    		m_exception_msq = new TMessageQue<SocketSessionExp>();
    		CSession::m_exception_msq=m_exception_msq;
    	}
    	~CSessionManager();//不是重点未给出
    private:
    	static TMessageQue<SocketSessionExp> *m_exception_msq;//在构造函数中new一个类对象
    	std::map<int,CSession*>			m_sessionMap;
    }
    
    

    该模块编译时没报错,链接时报错提示:

    undefined reference to `Network::CSession::m_exception_msq'
    

    2.试错

    CSessionManager是CSession的友元类,可直接访问CSession的私有成员和保护成员。也尝试通过函数、局部CSession等方式来完成m_exception_msq的赋值,均报错。

    3.分析与百度

    class CSession
    {
    	friend class CSessionManager;
    	public:
    		CSession();
    		virtual ~CSession();
    	private:
    		static TMessageQue<SocketSessionExp> *m_exception_msq;//TMessageQue为消息队列模板类
    }
    

    分析-有用信息:

    1. 在如上代码中,m_exception_msq只是声明,并没有定义和初始化。
    2. “undefined reference to”是未定义……;
    3. 项目中有地方使用静态变量的地方都在.cpp文件上方进行了初始化(实际是定义–>初始化)。

    分析推测:应该是m_exception_msq未定义。

    在.cpp文件中添加如下代码:

    //xxx.cpp
    TMessageQue<SocketSessionExp>* CSession::m_exception_msq=NULL;
    

    编译成功、链接成功、通过打印信息也看到CSession::m_exception_msq在CSessionManager构造中完成了赋值,问题解决了。

    这里一方面是对static成员变量的理解不到位,另一方面是分析的时候没有抓住有效信息浪费了不少时间。(“undefined reference to”)

    4.C++静态成员变量

    C++的变量的类型大致有普通成员变量、静态成员变量、成员常量这三种,还有一种组合的静态成员常量。

    这里说一下C++静态成员变量,在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。

    static成员的所有者是类本身和对象,但是多个对象拥有一样的静态成员。从而在定义对象时不能通过构造函数对其进行初始化; 静态成员不能在类定义里边初始化,只能在class body外初始化; 静态变量依旧符合public、private、protect特性; 静态成员函数没有this指针,它不能返回非静态成员,因为除了对象会调用它外,类本身也可以调用 。

    C++静态成员变量:

    1. 必须在外部定义和赋值;
      • 不能在 main() 函数中定义
      • 不能在类的构造函数中定义
    2. 必须要定义静态变量,否则该变量没有内存空间(类中只是申明) ;
    3. 类本身可以直接调用静态变量
    4. 静态变量依旧符合public、private、protect特性

    C++成员变量声明、初始化、赋值说明列表:

    数据成员类型normalconststaticstatic const
    类内直接初始化(在声明时就赋值)×
    先声明再通过初始化列表赋初值××
    先声明再在构造函数体里赋初值×××
    先声明再在类外赋初值××

    5.C++静态成员方法

    1、静态方法可以被类直接调用,但是同静态变量一样符合public、private、protect特性

    2、静态成员函数不可以调用类的非静态成员。因为静态成员函数不含this指针。

    3、静态成员函数不可以同时声明为 virtual或后缀const 函数。因为virtual就是用来区分是哪个对象调用了他,与静态方法矛盾。而后缀const是用来修饰this指针的,静态变量中不包含this指针。

    参考资料:
    https://blog.csdn.net/nwd0729/article/details/47067549
    https://blog.csdn.net/buknow/article/details/80275191

    展开全文
  • 静态变量初始化线程安全

    千次阅读 2019-01-03 17:47:36
    但是老的c++标准并没有担保,所以说老版本的编译器可能static 变量初始化多线程的条件下会造成问题 c++ 98/03 关于静态初始化标准 简言而之,它只是担保了local static 变量的初始化发生于当该表达式第一执行...
    前言

    c++11 担保了 static 变量的初始化线程安全。但是老的c++标准并没有担保,所以说老版本的编译器可能static 变量初始化在多线程的条件下会造成问题

    c++ 98/03 关于静态初始化标准

    下面是老版本标准对这个问题的描述,简言而之它只是担保了local static 变量的初始化发生于当该表达式第一次执行时。

    Here’s an excerpt from section 6.7 of a working draft (N1095) of the current C++ standard (C++98)
    The zero-initialization (8.5) of all local objects with static storage duration (3.7.1) is performed before any other initialization takes place. A local object of POD type (3.9) with static storage duration initialized with constant-expressions is initialized before its block is first entered. An implementation is permitted to perform early initialization of other local objects with static storage duration under the same conditions that an implementation is permitted to statically initialize an object with static storage duration in namespace scope (3.6.2). Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization.

    大多数编译器选择 在 全局作用域内的static 变量会在进入main函数前初始化,而 func内的local static 变量只会在该函数第一次被调用的时候初始化。这就造成了一个问题,可能函数内部的static local 变量的初始化不是线程安全的,所以我们不能假设 static local 变量的初始化就是线程安全的。

    编译器的实现

    demo
    #include <iostream>
    
    using namespace std;
    
    class Foo {
    public:
        Foo(const char* s = "") {
            cerr << "Constructing Foo with " << s << endl;
        }
    };
    
    void somefunc()
    {
        static Foo funcstatic("funcstatic");
        Foo funcauto("funcauto");
    }
    
    static Foo glob("global");
    
    int main()
    {
        cerr << "Entering main\n";
        somefunc();
        somefunc();
        somefunc();
        return 0;
    }
    
    vs2008 实现

    现在看看somefunc 这个 local static 变量初始化函数的实现。

        static Foo funcstatic("funcstatic");
    00E314FD  mov         eax,dword ptr [$S1 (0E3A148h)]
    00E31502  and         eax,1
    00E31505  jne         somefunc+71h (0E31531h)
    00E31507  mov         eax,dword ptr [$S1 (0E3A148h)]
    00E3150C  or          eax,1
    00E3150F  mov         dword ptr [$S1 (0E3A148h)],eax
    00E31514  mov         dword ptr [ebp-4],0
    00E3151B  push        offset string "funcstatic" (0E3890Ch)
    00E31520  mov         ecx,offset funcstatic (0E3A14Ch)
    00E31525  call        Foo::Foo (0E31177h)
    00E3152A  mov         dword ptr [ebp-4],0FFFFFFFFh
        Foo funcauto("funcauto");
    00E31531  push        offset string "funcauto" (0E38900h)
    00E31536  lea         ecx,[ebp-11h]
    00E31539  call        Foo::Foo (0E31177h)
    

    从上面汇编看到编译器对于是否初始化只是简单的通过一个计数器的判断如下面汇编代码。那么就有可能出现俩个线程得到 0E3A148h 这个地址的值都为0,那么这个时候就会发生初始化执行俩次。这个实现也符合 老版本 c++ 标准,所以没问题

    00E314FD  mov         eax,dword ptr [$S1 (0E3A148h)]
    00E31502  and         eax,1
    00E31505  jne         somefunc+71h (0E31531h)
    
    gcc 实现

    gcc 4.0 版本以上的实现,使用相同的代码 使用 g++ -O0 -g 编译。从下面的汇编可以看到 gcc 使用了 guard_acquire/release 担保了它的线程安全。
    gcc 可以使用-fno-threadsafe-statics 这个选项来关闭对 static local 变量多余的线程安全的开销调用。如果关闭了生成的代码和 vs2008差不多。另一方面说,这段代码引入了一些不可移植的问题。这段代码跑在gcc上编译就没问题,使用 vs2008就不行。

    0000000000400a9d <_Z8somefuncv>:
      400a9d:  55                      push   rbp
      400a9e:  48 89 e5                mov    rbp,rsp
      400aa1:  48 83 ec 40             sub    rsp,0x40
      400aa5:  b8 a8 21 60 00          mov    eax,0x6021a8
      400aaa:  0f b6 00                movzx  eax,BYTE PTR [rax]
      400aad:  84 c0                   test   al,al
      400aaf:  75 76                   jne    400b27 <_Z8somefuncv+0x8a>
      400ab1:  bf a8 21 60 00          mov    edi,0x6021a8
      400ab6:  e8 cd fd ff ff          call   400888 <__cxa_guard_acquire@plt>
      400abb:  85 c0                   test   eax,eax
      400abd:  0f 95 c0                setne  al
      400ac0:  84 c0                   test   al,al
      400ac2:  74 63                   je     400b27 <_Z8somefuncv+0x8a>
      400ac4:  c6 45 df 00             mov    BYTE PTR [rbp-0x21],0x0
      400ac8:  be aa 0c 40 00          mov    esi,0x400caa
      400acd:  bf b0 21 60 00          mov    edi,0x6021b0
      400ad2:  e8 89 00 00 00          call   400b60 <_ZN3FooC1EPKc>
      400ad7:  c6 45 df 01             mov    BYTE PTR [rbp-0x21],0x1
      400adb:  bf a8 21 60 00          mov    edi,0x6021a8
      400ae0:  e8 03 fe ff ff          call   4008e8 <__cxa_guard_release@plt>
      400ae5:  eb 40                   jmp    400b27 <_Z8somefuncv+0x8a>
      400ae7:  48 89 45 c8             mov    QWORD PTR [rbp-0x38],rax
      400aeb:  48 89 55 d0             mov    QWORD PTR [rbp-0x30],rdx
      400aef:  8b 45 d0                mov    eax,DWORD PTR [rbp-0x30]
      400af2:  89 45 ec                mov    DWORD PTR [rbp-0x14],eax
      400af5:  48 8b 45 c8             mov    rax,QWORD PTR [rbp-0x38]
      400af9:  48 89 45 e0             mov    QWORD PTR [rbp-0x20],rax
      400afd:  0f b6 45 df             movzx  eax,BYTE PTR [rbp-0x21]
      400b01:  83 f0 01                xor    eax,0x1
      400b04:  84 c0                   test   al,al
      400b06:  74 0a                   je     400b12 <_Z8somefuncv+0x75>
      400b08:  bf a8 21 60 00          mov    edi,0x6021a8
      400b0d:  e8 06 fe ff ff          call   400918 <__cxa_guard_abort@plt>
      400b12:  48 8b 45 e0             mov    rax,QWORD PTR [rbp-0x20]
      400b16:  48 89 45 c8             mov    QWORD PTR [rbp-0x38],rax
      400b1a:  48 63 45 ec             movsxd rax,DWORD PTR [rbp-0x14]
      400b1e:  48 8b 7d c8             mov    rdi,QWORD PTR [rbp-0x38]
      400b22:  e8 11 fe ff ff          call   400938 <_Unwind_Resume@plt>
      400b27:  48 8d 7d ff             lea    rdi,[rbp-0x1]
      400b2b:  be b5 0c 40 00          mov    esi,0x400cb5
      400b30:  e8 2b 00 00 00          call   400b60 <_ZN3FooC1EPKc>
      400b35:  c9                      leave
      400b36:  c3                      ret
    
    总结

    使用老版本编译器编译c++代码,还是遵循标准不要做任何假设。

    参考

    https://eli.thegreenplace.net/2011/08/30/construction-of-function-static-variables-in-c-is-not-thread-safe

    展开全文
  • 1. 如果是编译时和加载时初始化,... 而这些初始化一定是在单线程环境操作的! -- 都是在执行C Runtime的startup代码中的void mainCRTStartup(void)函数时所在的OS系统加载程序时的主线程空间上发生的! 2. 如果是运...

    1. 如果是编译时和加载时初始化, 是不会存在线程安全这个issue的;  

           因为这两种初始化一定发生在Main函数执行之前, 这个时候尚未进入程序运行空间; 而这些初始化一定是在单线程环境下操作的!  --  都是在执行C Runtime的startup代码中的void mainCRTStartup(void)函数时所在的OS系统加载程序时的主线程空间上发生的!

    2. 如果是运行时初始化, 因为无法保证访问这个静态变量所在的局部函数/全局函数/类成员函数/类静态成员函数  一定只会从某个特定的线程中被访问, 因此, 就一定会存在"线程安全"的issue!

    展开全文
  • 静态变量初始化的时机

    千次阅读 2017-10-02 16:40:48
    静态变量的内存分配和初始化 对于C语言的全局和静态变量,不管是否被初始化,其内存空间都是全局的;如果初始化,那么初始化发生在任何代码执行之前,属于编译期初始化。由于内置变量无须资源释放操作,仅需要...
  • C++静态变量为何只能初始化

    千次阅读 2014-02-11 23:35:22
    static 关键字的作用: ...static全局变量是限定作用域的全局变量。  static函数只能被本文件里的内容使用(相当于私有函数),是限定作用域的全局函数。  C++里头的static函数是相对成员函数而言
  • 原文:http://www.cppblog.com/lai3d/archive/2009/07/08/89514.html未初始化的bool成员变量在Debug默认值为false,Test默认true。一个bug查了一晚上,原因就是这个.人物创建的场景在Debug正常,在Test和...
  • 1. 在类中,只是声明了静态变量,并没有定义。// 普通变量也是声明,然后在实例对象时定义 2. 声明只是表明了变量的数据类型和属性,并不分配内存;定义则是需要分配内存的。 注意:如果在类里面这么写int a; ...
  • c#多线程应用和静态变量

    千次阅读 2010-12-26 10:19:00
    在c#开发过程中,不可避免要用到多线程。当在子线程中访问主UI线程中的控件时,可以用委托,控件的invoke等。也可以设置全局静态变量CheckForIllegalCrossThreadCalls:CheckForIllegalCrossThreadCalls = false;//...
  • 多线程程序中,无论我们使用AfxBeginThread ,CreateThread,_beginthread构造线程函数,因为线程函数只能是全局函数或静态函数,下面拿静态函数来举例说明,静态函数中可以直接访问静态成员,但是访问类的非静态...
  • C++ 静态变量之为什么只初始化

    千次阅读 2013-08-28 07:29:23
    以下内容由在论坛中讨论而成,在此总结一下: ...当这个函数被反复调用时,i的值是会一直加的,也就是静态变量只被初始化了一. 我对此产生了疑惑.不知道大家有没有. 当改为: [cpp]  int fun()  { 
  • 经常听到,类的static变量在类加载时就会初始化,于是有了常说的两种单例模式的对比:饿汉式和静态内部类模式。通常的说法是,两种都是支持线程安全的(关于怎么个安全法请看我上面的链接),饿汉式不被推荐是因为会...
  • 什么时候初始化 根据 C++ 标准,全局变量初始化要在 main 函数执行前完成,常识无疑,但是这个说法...答案是既有编译时,也可能会有运行时(seriously), 从语言的层面来说,全局变量初始化可以划分为以下两
  • Imageloader<5>-ImageLoader的变量初始化

    千次阅读 2015-12-08 21:23:06
    UIHandler可以在loadImage时初始化,其余的变量统一在init方法中初始化。getInstance提供让用户自定义线程池线程数量和加载策略的方法。... * 静态成员变量 */ private static NewImageLoader mImageLoader ; /**
  • 关于在类中使用static的一些情况:   静态成员函数和静态成员变量的调用格式,尽量采用类名::成员的格式,不要以对象来调用 <br />1. static func静态成员函数  1) 其地址可以直接由...
  • 静态(static)变量初始化

    千次阅读 2013-02-22 15:31:54
    还有个问题,我们抓取函数是静态函数,这意味着我们不能构造一个实例,在里面先初始化好一个Proxy成员变量,然后给抓取函数调用。 这也不行,那也不行,愁煞寡人。 十月革命一声炮响,后来想到静态变量。将proxy作为...
  • 这两天写一个简单的程序,由于程序运行占用cpu比较厉害,导致运行中界面窗口无法交互,因此想到了多线程,以前没有接触过mfc多线程,在网上看了两篇文章,觉得也不过如此,就开始动手写了,结果发现即使是看...
  • 基本数据类型数值6类 (long/int/short/byte)(double/float) 非数值2类(char,boolean)下面是默认值:0/0/0/0/0.0/0.0/ /false首先 Java 语言就是这么规定的。然后为什么 Java 语言要这么规定...而成员变量就是类的数...
  • C++类静态成员与类静态成员函数    当将类的某个数据成员声明为static时,该静态数据成员只能被定义一,而且要被同类的所有对象共享。各个对象都拥有类中每一个普通数据成员的副本,但静态数据成员只有一个...
  • 莫偷懒!成员变量一定要初始化!

    千次阅读 2014-04-22 14:35:01
    初始化的bool成员变量在Debug默认值为false,Test默认true。一个bug查了一晚上,原因就是这个. 人物创建的场景在Debug正常,在Test和Release不正常,就是镜头不对。然后就盯着这个载入场景的配置文件的...
  • 非局部变量初始化议题讨论

    千次阅读 2008-06-12 17:51:00
    非局部变量初始化规则和现实中跨编译单元的初始化顺序依赖的种解决方案。 文中的内容都源自一些C++书籍(BS的TCPL,Sutter的Exceptional系列),库的源代码和MSDN。 1.非局部变量的定义 非局部变量包括全局...
  • 万字图解Java多线程

    万次阅读 多人点赞 2020-09-06 14:45:07
    java多线程我个人觉得是javaSe中最难的一部分,我以前也是感觉学会了,但是真正有多线程的需求却不知道怎么下手,实际上还是对多线程这块知识了解不深刻,不知道多线程api的应用场景,不知道多线程的运行流程等等,...
  • 类的静态成员延迟初始化要求静态成员只能被初始化,也有类似的问题。 在单线程环境,这事儿很好办。Singleton* Singleton::getInstance() { if (m_instance == nullptr) { m_instance = new Singleton;
  • C++总结之一 比较是学习的一个很有效的方法。c 被认为是最贴近机器...语言本身是人设计的,为了实现这些变化,操作系统本身是做了很的改动的。开发语言离开操作系统就变得没有意义。  正如大家知道,w
  • Java多线程中static变量的使用

    千次阅读 2016-10-31 23:46:50
    有时候,对于在多线程中使用static变量有没有冲突,是否存在安全问题不能十分的确定。在使用过程中有点含糊,总想找点时间好好追究一下,可总因开发项目时间的紧迫而搁浅。我想,没有做进一步的研究而拿项目繁忙说事...
  • 前言:最近写代码的时候经常见到见到static代码块,不由对static的执行时间产生了兴趣,进而对类初始化顺序产生了兴趣. 类从编译到执行的过程: 在使用ClassLoader将字节码转换为JVM中的Class&lt;Robot&gt;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 102,118
精华内容 40,847
关键字:

多线程下静态成员变量初始化几次