Visual C++中的警告4355的意义

 

Visual C++中4355的警告(warning C4355: 'this' : used in base member initializer list),字面意思是this指针用在类成员初始化列表中。这个警告是怎么出现的呢?通过下面这个程序来说明:

 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include  <exception>
#include  <iostream>


class  Base
{
public :
    
explicit  Base()
    {
    }

    
virtual   void  init() =  0 ;

    
virtual   void  uninit() =  0 ;

};


class  Strategy
{
public :
    
explicit  Strategy( Base *p )
        : m_p( p )
    {
        m_p->init();
    }

    ~Strategy()
    {
        m_p->uninit();
    }

private :
    Base *m_p;

};


class  Derived :  public  Base
{
public :
    
explicit  Derived()
        : m_instance( 
this  )
        , pi( 
0  )
    {
        
throw  std::exception(  "The exception happened in the constructor of class Derived. "  );

        pi = 
new   int 0  );
    }

    ~Derived()
    {
        
delete  pi;
    }

    
virtual   void  init()
    {
    }

    
virtual   void  uninit()
    {
        *pi = 
500 ;
    }

private :
    Strategy m_instance;

    
int  *pi;
};


int  main(  int  argc,  char  *argv[] )
{
    
try
    {
        Derived temp;
    }
// try
     catch ( std::exception &e )
    {
        std::cout << e.what() << 
"\n"  ;
    }
    
catch ( ... )
    {
        std::cout << 
"Unknown exception has been caught! \n"  ;
    }
// catch

    
return  (  0 );
}

 

生成时编译器会报出4355警告。这个警告定位在Derived构造函数的成员初始化列表中,准确地说是m_instance( this )这里。那么这个警告的意义是什么呢?运行一下就知道——程序挂了。问题出在Derived::uninit方法,它在main函数结束时销毁temp对象调用析构函数后被调用,而其pi成员是个NULL,引用它的地址进行赋值操作当然就挂了。原因显而易见:Derived构造函数没执行完就异常退出,pi成员没有执行分配内存操作。也就是说,在构造函数执行结束前发生异常,那么这个对象就是不完整的,如果用成员初始化列表的方式把这个对象的this指针拿去构造另一个对象就会有安全隐患,因为后者也不是一个完整的对象。

我是在ACE(5.6)一个Reactor示例中发现的这个问题,上例中的Strategy和Base分别模拟ACE_Reactor_Notification_Strategy和ACE_Svc_Handler。库的作者设计了抽象类和策略类之间的构造关系,使用者在实现时常会出现这个问题。解决方法一:把Derived中的Strategy成员改为指针成员,然后在初始化方法中用this指针创建它的实例即可。优点是确保安全且无编译警告,缺点是使用时多了一个初始化调用操作。解决方法二:也是使用Strategy指针成员,但其对象实例的创建放在构造函数最后,并确保之前的构造调用无异常或异常安全。优点正是避免了上一种解决方法的缺点,而缺点就是仍然有编译警告。

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

弟十六

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值