Skip to content

Commit b70fe61

Browse files
committed
更新内容
1 parent 4ab9bed commit b70fe61

File tree

5 files changed

+273
-3
lines changed

5 files changed

+273
-3
lines changed

C++/GDB_Debug.md

+58-1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,62 @@ GDB是UNIX下面的程序调试工具, 可以调试多种类型程序, 主要可
118118
[Inferior 1 (process 8845) exited normally] ----> 程序退出,调试结束
119119
(gdb) q
120120

121+
# core dump 调试
122+
123+
当程序异常退出时,操作系统把程序当前的内存状况存储在一个core文件中,该文件包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等。通过分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。
124+
125+
首先要确定当前会话的 ulimit –c,若为0,则不会产生对应的coredump,需要进行修改和设置,`ulimit –c [size]`(注意,这里的size如果太小,则可能不会产生对应的core文件)。
126+
127+
```
128+
ulimit -c unlimited (可以产生core dump 且不受大小限制)
129+
```
130+
131+
core文件默认的存储位置为当前进程的工作目录(一般就是可执行文件所在的目录)。当程序出现段错误(试图访问或者修改不属于自己的内存地址时)时,就会产生 core dump,方便我们进行调试。下面是一些常见的段错误:
132+
133+
* 内存访问越界:由于使用错误的下标,导致数组访问越界。
134+
* 非法指针访问:比如写 nullptr
135+
* 栈溢出:使用了大的局部变量
136+
137+
下面是个简单的例子:
138+
139+
```c++
140+
#include <iostream>
141+
using namespace std;
142+
143+
void test(){
144+
int *p = nullptr;
145+
*p = 1; // Segment Fault
146+
}
147+
int main() {
148+
test();
149+
return 0;
150+
}
151+
```
152+
153+
然后编译运行程序,用 GDB 查看其产生的 Core Dump 文件:
154+
155+
```bash
156+
$ g++ -g demo.cpp -o demo.o -std=c++11
157+
$ ulimit -c
158+
0
159+
$ ulimit -c unlimited
160+
$ ./demo.o
161+
[1] 15193 segmentation fault (core dumped) ./demo.o
162+
$ ~ ls
163+
core demo.cpp demo.o
164+
~ gdb demo.o core
165+
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
166+
Copyright (C) 2014 Free Software Foundation, Inc.
167+
......
168+
Core was generated by './demo.o'.
169+
Program terminated with signal SIGSEGV, Segmentation fault.
170+
#0 0x00000000004006dd in test () at demo.cpp:6
171+
6 *p = 1;
172+
(gdb) bt
173+
#0 0x00000000004006dd in test () at demo.cpp:6
174+
#1 0x00000000004006ee in main () at demo.cpp:9
175+
```
176+
121177
# 调试参数
122178

123179
gdb调试中需要用到的命令
@@ -177,13 +233,14 @@ gdb调试中需要用到的命令
177233

178234
![][1]
179235

180-
181236
# 参考
182237

183238
[使用gdb调试程序详解](http://www.vimer.cn/2009/11/使用gdb调试程序详解.html)
184239
[GDB中应该知道的几个调试方法](http://coolshell.cn/articles/3643.html)
185240
[Codesign gdb on Mac OS X Yosemite](http://andresabino.com/2015/04/14/codesign-gdb-on-mac-os-x-yosemite-10-10-2/)
241+
[详解 coredump](http://blog.csdn.net/tenfyguo/article/details/8159176)
186242
[C++编译器无法捕捉到的8种错误](http://blog.jobbole.com/15837/)
243+
[What is a segmentation fault?](http://stackoverflow.com/questions/2346806/what-is-a-segmentation-fault)
187244

188245
[1]: http://7xrlu9.com1.z0.glb.clouddn.com/C++_GDB_Debug_1.png
189246

C++/Keywords.md

+21
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,27 @@ struct B : A
331331
不过注意 override 和 final 一样,不是C++保留字:
332332

333333
> Note that neither override nor final are language keywords. They are technically identifiers; they only gain special meaning when used in those specific contexts. In any other location, they can be valid identifiers.
334+
335+
# new 操作符
336+
337+
new和delete对堆中的内存进行申请和释放,而且这两个操作符是不能被重载的。要实现不同的内存分配行为,需要重载operator new,而不是new和delete。
338+
339+
看如下代码:
340+
341+
class foo{};
342+
foo* pfoo = new foo;
343+
344+
这里的new实际上是执行如下3个过程:
345+
346+
1. 调用operator new分配内存;
347+
2. 调用构造函数生成类对象;
348+
3. 返回相应指针。
349+
350+
operator new 就像 operator+ 一样,是可以重载的,但是不能在全局对原型为void operator new(size_t size)这个原型进行重载,一般只能在类中进行重载。
351+
352+
如果类中没有重载operator new,那么调用的就是全局的::operator new来完成堆的分配。同理,operator new[]、operator delete、operator delete[]也是可以重载的。
353+
354+
new 操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。
334355

335356
# 更多阅读
336357

C++/More.md

+107-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
//
4242
// 注册需要在 main 函数结束后执行的函数.
4343
// 请注意它们的注册顺序和执行顺序
44-
// 在 main 函数结束后被调用,调用顺序与注册顺序相反。 先注册后执行。
44+
// 在 main 函数结束后被调用,调用顺序与注册顺序相反。先注册后执行。
4545
//
4646

4747
atexit(fn1);
@@ -112,6 +112,109 @@ IEEE 754 标准所定义的单精度浮点数所表示的数的范围大约为 
112112
cout << setprecision(10) << c << endl; // 54
113113

114114
[double 精度丢失](http://www.nowcoder.com/questionTerminal/d12c2556b4614d8b87a7b64d0d0c24bb)
115+
116+
# placement new
117+
118+
placement new 是operator new的一个重载版本,只是我们很少用到它。用它可以在已经分配好的内存中(栈或堆中)构建新的对象,这个构建过程不需要额外分配内存,只需要调用对象的构造函数即可。
119+
120+
它的原型如下:
121+
122+
void *operator new( size_t, void *p ) throw(){
123+
return p;
124+
}
125+
126+
void *p 实际上就是指向一个已经分配好的内存缓冲区的的首地址。
127+
128+
举例来说:
129+
130+
class foo{};
131+
foo* pfoo = new foo;
132+
133+
pfoo指向的对象的地址你是不能决定的,因为new已经为你做了这些工作。第一步分配内存,第二步调用类的构造函数。而placement new是怎么做的呢,说白了就是把原本new做的两步工作分开来。第一步你自己分配内存,第二步你调用类的构造函数在自己分配的内存上构建新的对象。placement new的好处:
134+
135+
1. 在已分配好的内存上进行对象的构建,构建速度快。
136+
2. 已分配好的内存可以反复利用,有效的避免内存碎片问题。
137+
138+
在很多情况下,placement new的使用方法和其他普通的new有所不同。
139+
140+
### 1. 缓存提前分配
141+
142+
为了保证通过placement new使用的缓存区的memory alignmen(内存队列)正确准备,使用普通的new来分配它:
143+
144+
class Task ;
145+
char * buff = new [sizeof(Task)]; //分配内存
146+
147+
### 2. 对象的分配
148+
149+
在刚才已分配的缓存区调用 placement new 来构造一个对象。
150+
151+
Task *ptask = new(buff) Task;
152+
153+
### 3. 使用
154+
155+
按照普通方式使用分配的对象:
156+
157+
ptask->suspend();
158+
ptask->resume();
159+
160+
### 4. 对象的销毁
161+
162+
一旦你使用完这个对象,你必须调用它的析构函数来销毁它。按照下面的方式调用析构函数:
163+
164+
ptask->~Task(); //调用外在的析构函数
165+
166+
### 5. 释放
167+
168+
可以反复利用缓存并给它分配一个新的对象(重复步骤2,3,4)。如果不打算再次使用这个缓存,你可以象这样释放它:
169+
170+
delete [] buff;
171+
172+
跳过任何步骤就可能导致运行时间的崩溃,内存泄露,以及其它的意想不到的情况。
173+
174+
### 6. 建立对象数组
175+
176+
placement new 还可以用来建立带参数的构造函数对象数组。
177+
178+
#include <iostream>
179+
#include <new>
180+
using namespace std;
181+
182+
class CPong
183+
{
184+
public:
185+
CPong(int m) : v(m) {
186+
cout << "CPong constructor" << v << endl;
187+
cout << this << endl;
188+
}
189+
190+
private:
191+
int v;
192+
};
193+
194+
int main(){
195+
const int arr_size = 3;
196+
char* pong = new char[sizeof(CPong) * arr_size];
197+
CPong* pp = (CPong*)pong;
198+
199+
for (int i=0; i<arr_size; ++i )
200+
{
201+
new (pp+i)CPong(i); // 对象构造函数
202+
}
203+
204+
for (int i=0; i<arr_size; ++i )
205+
{
206+
new (pp+i)CPong(i+arr_size);
207+
}
208+
209+
for (int j=0; j<arr_size; ++j )
210+
{
211+
pp[j].~CPong();
212+
}
213+
214+
delete [] pong;
215+
return 0;
216+
}
217+
115218

116219
# 更多阅读
117220

@@ -120,4 +223,7 @@ IEEE 754 标准所定义的单精度浮点数所表示的数的范围大约为 
120223
[IEEE 754浮点数在机器中的格式](http://blog.csdn.net/glgoober/article/details/6209881)
121224
[一个浮点数跨平台产生的问题](http://coolshell.cn/articles/11235.html)
122225
[float and double](http://www.cplusplus.com/forum/beginner/83526/)
226+
[Placement new的用法及用途](http://www.cppblog.com/kongque/archive/2010/02/20/108093.html)
227+
[遵循placement new的用法规范](http://www.cnblogs.com/felixYeou/archive/2009/04/15/1436209.html)
228+
123229

DataBase/Design.md

+5
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@
145145
# 更多阅读
146146

147147
[解释一下关系数据库的第一第二第三范式?](https://www.zhihu.com/question/24696366)
148+
[数据库设计之概念结构设计:E-R图详解](http://blog.csdn.net/zxq1138634642/article/details/9121363)
149+
[数据库设计 Step by Step (1)](http://www.cnblogs.com/DBFocus/archive/2011/03/27/1996655.html)
150+
[数据库设计 Step by Step (2)——数据库生命周期](http://www.cnblogs.com/DBFocus/archive/2011/04/09/2010904.html)
151+
[数据库设计 Step by Step (3)——基本ER模型构件](http://www.cnblogs.com/DBFocus/archive/2011/04/24/2026142.html)
152+
148153

149154
[1]: http://7xrlu9.com1.z0.glb.clouddn.com/DatabaseSystem_Design_1.png
150155
[2]: http://7xrlu9.com1.z0.glb.clouddn.com/DatabaseSystem_Design_2.png

0 commit comments

Comments
 (0)