外传三 动态内存申请的结果

问题:

动态内存申请一定成功吗?

 问题:

new语句中的异常是怎么抛出来的?

 

一般我们会在new_handler函数中进行内存的整理,整理之后再次申请。

问题:

如何跨编译器统一new的行为,提高代码移植性?

全局定义new就是全局new操作符的重载。

最后两种方法是推荐的做法。

使用nothrow时,new失败了会返回空指针。

 示例程序:

 1 #include <iostream>
 2 #include <new>
 3 #include <cstdlib>
 4 #include <exception>
 5 
 6 using namespace std;
 7 
 8 class Test
 9 {
10     int m_value;
11 public:
12     Test()
13     {
14         cout << "Test()" << endl;
15         
16         m_value = 0;
17     }
18     
19     ~Test()
20     {
21         cout << "~Test()" << endl;  
22     }
23     
24     void* operator new (unsigned int size) 25     {
26         cout << "operator new: " << size << endl;
27         
28         // return malloc(size);
29         
30         return NULL;
31     }
32     
33     void operator delete (void* p)
34     {
35         cout << "operator delete: " << p << endl;
36         
37         free(p);
38     }
39     
40     void* operator new[] (unsigned int size) 41     {
42         cout << "operator new[]: " << size << endl;
43         
44         // return malloc(size);
45         
46         return NULL;
47     }
48     
49     void operator delete[] (void* p)
50     {
51         cout << "operator delete[]: " << p << endl;
52         
53         free(p);
54     }
55 };
56 
57 void my_new_handler()
58 {
59     cout << "void my_new_handler()" << endl;
60 }
61 
62 void ex_func_1()
63 {
64     new_handler func = set_new_handler(my_new_handler);
65     
66     try
67     {
68         cout << "func = " << func << endl;
69         
70         if( func )
71         {
72             func();
73         }
74     }
75     catch(const bad_alloc&)
76     {
77         cout << "catch(const bad_alloc&)" << endl;
78     }
79 }
80 
81 
82 int main(int argc, char *argv[])
83 {
84     ex_func_1();
85     
86     return 0;
87 }

第64行用于将我们自己的new处理函数设置进去并且返回编译器默认的new处理函数,并赋值给func,运行结果如下:

打印结果为0,说明了编译器没有默认的new处理函数。

vs2010的运行结果如下:

bcc编译器的结果如下:

可以看到bcc编译器是有默认的new处理函数的。

而且func函数确实抛出了bad_alloc异常。

第二个实验函数:

81行的new行为调用了Test类重载的new操作符,new操作符返回NULL(这是我们人为设置的),并且在NULL指针上执行了构造函数,这个构造函数中有成员变量的赋值操作,因此,导致了段错误。

上述程序在vs2010上结果如下:

这说明了如果重载的new操作符返回了NULL,那么是不会调用构造函数的。

同样的程序,bcc编译器的行为如下:

和vs的结果是一样的。

这三个编译器的行为是不统一的。

因此,我们要对程序进行改进,如下:

 1 #include <iostream>
 2 #include <new>
 3 #include <cstdlib>
 4 #include <exception>
 5 
 6 using namespace std;
 7 
 8 class Test
 9 {
10     int m_value;
11 public:
12     Test()
13     {
14         cout << "Test()" << endl;
15         
16         m_value = 0;
17     }
18     
19     ~Test()
20     {
21         cout << "~Test()" << endl;  
22     }
23     
24     void* operator new (unsigned int size) throw()
25     {
26         cout << "operator new: " << size << endl;
27         
28         // return malloc(size);
29         
30         return NULL;
31     }
32     
33     void operator delete (void* p)
34     {
35         cout << "operator delete: " << p << endl;
36         
37         free(p);
38     }
39     
40     void* operator new[] (unsigned int size) throw()
41     {
42         cout << "operator new[]: " << size << endl;
43         
44         // return malloc(size);
45         
46         return NULL;
47     }
48     
49     void operator delete[] (void* p)
50     {
51         cout << "operator delete[]: " << p << endl;
52         
53         free(p);
54     }
55 };
56 
57 void my_new_handler()
58 {
59     cout << "void my_new_handler()" << endl;
60 }
61 
62 void ex_func_1()
63 {
64     new_handler func = set_new_handler(my_new_handler);
65     
66     try
67     {
68         cout << "func = " << func << endl;
69         
70         if( func )
71         {
72             func();
73         }
74     }
75     catch(const bad_alloc&)
76     {
77         cout << "catch(const bad_alloc&)" << endl;
78     }
79 }
80 
81 void ex_func_2()
82 {
83     Test* pt = new Test();
84     
85     cout << "pt = " << pt << endl;
86     
87     delete pt;
88     
89 }
90 
91 
92 int main(int argc, char *argv[])
93 {
94     //ex_func_1();
95     ex_func_2();
96     
97     return 0;
98 }

我们在第24、40行的重载函数声明时加上了throw(),这就告诉编译器这个函数不抛出异常。

结果如下:

这样,这三款编译器的行为就统一了。

添加申请数组的实验:

  1 #include <iostream>
  2 #include <new>
  3 #include <cstdlib>
  4 #include <exception>
  5 
  6 using namespace std;
  7 
  8 class Test
  9 {
 10     int m_value;
 11 public:
 12     Test()
 13     {
 14         cout << "Test()" << endl;
 15         
 16         m_value = 0;
 17     }
 18     
 19     ~Test()
 20     {
 21         cout << "~Test()" << endl;  
 22     }
 23     
 24     void* operator new (unsigned int size) throw()
 25     {
 26         cout << "operator new: " << size << endl;
 27         
 28         // return malloc(size);
 29         
 30         return NULL;
 31     }
 32     
 33     void operator delete (void* p)
 34     {
 35         cout << "operator delete: " << p << endl;
 36         
 37         free(p);
 38     }
 39     
 40     void* operator new[] (unsigned int size) throw()
 41     {
 42         cout << "operator new[]: " << size << endl;
 43         
 44         // return malloc(size);
 45         
 46         return NULL;
 47     }
 48     
 49     void operator delete[] (void* p)
 50     {
 51         cout << "operator delete[]: " << p << endl;
 52         
 53         free(p);
 54     }
 55 };
 56 
 57 void my_new_handler()
 58 {
 59     cout << "void my_new_handler()" << endl;
 60 }
 61 
 62 void ex_func_1()
 63 {
 64     new_handler func = set_new_handler(my_new_handler);
 65     
 66     try
 67     {
 68         cout << "func = " << func << endl;
 69         
 70         if( func )
 71         {
 72             func();
 73         }
 74     }
 75     catch(const bad_alloc&)
 76     {
 77         cout << "catch(const bad_alloc&)" << endl;
 78     }
 79 }
 80 
 81 void ex_func_2()
 82 {
 83     Test* pt = new Test();
 84     
 85     cout << "pt = " << pt << endl;
 86     
 87     delete pt;
 88     
 89     pt = new Test[5];
 90     
 91     cout << "pt = " << pt << endl;
 92     
 93     delete[] pt; 
 94 }
 95 
 96 int main(int argc, char *argv[])
 97 {
 98     // ex_func_1();
 99     ex_func_2();
100     
101     return 0;
102 }

结果如下:

linux:

vs2010:

bcc:

 实验三:

在单次申请的时候告诉编译器,不管结果是什么都不要抛出异常,如果申请失败返回空指针。

 1 #include <iostream>
 2 #include <new>
 3 #include <cstdlib>
 4 #include <exception>
 5 
 6 using namespace std;
 7 
 8 class Test
 9 {
10     int m_value;
11 public:
12     Test()
13     {
14         cout << "Test()" << endl;
15         
16         m_value = 0;
17     }
18     
19     ~Test()
20     {
21         cout << "~Test()" << endl;  
22     }
23     
24     void* operator new (unsigned int size) throw()
25     {
26         cout << "operator new: " << size << endl;
27         
28         // return malloc(size);
29         
30         return NULL;
31     }
32     
33     void operator delete (void* p)
34     {
35         cout << "operator delete: " << p << endl;
36         
37         free(p);
38     }
39     
40     void* operator new[] (unsigned int size) throw()
41     {
42         cout << "operator new[]: " << size << endl;
43         
44         // return malloc(size);
45         
46         return NULL;
47     }
48     
49     void operator delete[] (void* p)
50     {
51         cout << "operator delete[]: " << p << endl;
52         
53         free(p);
54     }
55 };
56 
57 void my_new_handler()
58 {
59     cout << "void my_new_handler()" << endl;
60 }
61 
62 void ex_func_3()
63 {
64     int* p = new(nothrow) int[10];
65     
66     // ... ...
67     
68     delete[] p; 
69     
70     int bb[2] = {0};
71     
72     struct ST
73     {
74         int x;
75         int y;
76     };
77     
78     ST* pt = new(bb) ST();
79     
80     pt->x = 1;
81     pt->y = 2;
82     
83     cout << bb[0] << endl;
84     cout << bb[1] << endl;
85     
86     pt->~ST();
87 }
88 
89 int main(int argc, char *argv[])
90 {
91 
92     ex_func_3();
93     
94     return 0;
95 }

第64行告诉编译器无论成功失败都不要抛出异常,第78行是在指定的位置创建对象,在这里我们是通过new在栈上创建对象,在第86行我们手动的调用析构函数。在这里不能delete pt指针。

结果如下:

bcc下结果:

vs结果:

可以看到三款编译器的结果全部一致。

猜你喜欢

转载自www.cnblogs.com/wanmeishenghuo/p/9610114.html