Skip to content

Commit

Permalink
udpate c++
Browse files Browse the repository at this point in the history
  • Loading branch information
selfboot committed Aug 22, 2016
1 parent c403be1 commit 32fd4b6
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 18 deletions.
2 changes: 1 addition & 1 deletion C++/11_Lambda.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
return 0;
}

在by_val_lambda中,j被视为一个常量,一旦初始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量),而在by_ref_lambda中,j仍然在使用父作用域中的值。所以,在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。
在by_val_lambda中,j 被视为一个常量,一旦初始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量),而在by_ref_lambda中,j仍然在使用父作用域中的值。所以,在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。

再来看一段代码:

Expand Down
35 changes: 33 additions & 2 deletions C++/11_SmartPoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,45 @@ shared_ptr名如其名,它允许多个该智能指针共享地“拥有”同

要解决环形引用的问题,没有特别好的办法,一般都是在可能出现环形引用的地方使用weak_ptr来代替shared_ptr。

### [weak_ptr](http://en.cppreference.com/w/cpp/memory/weak_ptr)

weak_ptr一般和shared_ptr配合使用,它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数。这样就有可能出现weak_ptr所指向的对象实际上已经被释放了的情况。因此,weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。

> std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.
下面是一个简单的例子:

```c++
#include <iostream>
#include <memory>

std::weak_ptr<int> gw;
void f() {
if (auto spt = gw.lock()) { // Has to be copied into a shared_ptr before usage
std::cout << *spt << "\n";
}
else {
std::cout << "gw is expired\n";
}
}

int main() {
{
auto sp = std::make_shared<int>(42);
gw = sp;
f();
}
f();
}
```

# 更多阅读

[C++ 引用计数技术及智能指针的简单实现](http://www.cnblogs.com/QG-whz/p/4777312.html)
[从auto_ptr说起](http://www.jellythink.com/archives/673)
[到C++11中的智能指针](http://www.jellythink.com/archives/684)
[Using smart pointers for class members](http://stackoverflow.com/questions/15648844/using-smart-pointers-for-class-members)

[C++11 新特性之智能指针](http://blog.jobbole.com/104569/)
[When is std::weak_ptr useful?](http://stackoverflow.com/questions/12030650/when-is-stdweak-ptr-useful)

[1]: http://7xrlu9.com1.z0.glb.clouddn.com/C++_11_SmartPoint_1.png
[2]: http://7xrlu9.com1.z0.glb.clouddn.com/C++_11_SmartPoint_2.png
Expand Down
2 changes: 1 addition & 1 deletion C++/C.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,5 @@ printf 函数是一个标准库函数,它的函数原型在头文件“stdio.h
[从Swap函数谈加法溢出问题](http://blog.csdn.net/dataspark/article/details/9703967)
[浅谈C语言中的位段](http://www.cnblogs.com/dolphin0520/archive/2011/10/14/2212590.html)
[C语言结构体里的成员数组和指针](http://coolshell.cn/articles/11377.html)

[深入理解C语言](http://coolshell.cn/articles/5761.html)

55 changes: 44 additions & 11 deletions C++/InputOutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,6 @@ I/O 操作一个与生俱来的问题是可能发生错误,I/O类定义了一
|setw(n) |设置字段宽度为n位
| setiosflags( ios::fixed) | 设置浮点数以固定的小数位数显示(ios::left 左对齐,ios::right 数据右对齐)

其它istream类方法如下:

* `cin.get(char &)`:从输入流中读取一个字符,赋给字符变量ch。如果读取成功则函数返回true(真),如失败(遇文件结束符) 则函数返回false(假)。
* `cin.get(void)`:从指定的输入流中提取一个字符(包括空白字符),函数的返回值就是读入的字符。若遇到输入流中的文件结束符,则函数值返回文件结束标志EOF(End Of File)。
* `get(char *, int, char)`:从输入流中读取n-1个字符,赋给指定的字符数组(或字符指针指向的数组),如果在读取n-1个字符之前遇到指定的终止字符,则提前结束读取。如果读取成功则函数返回true(真),如失败(遇文件结束符) 则函数返回false(假)。
* `getline(char*, int, char)`:从输入流中读取一行字符,其用法与带3个参数的get函数类似。默认是读取整行!

用getline函数从输入流读字符时,遇到终止标志字符时结束,指针移到该终止标志字符之后,下一个getline函数将从该终止标志的下一个字符开始接着读入。如果用cin.get函数从输入流读字符时,遇终止标志字符时停止读取,指针不向后移动,仍然停留在原位置,下一次读取时仍从该终止标志字符开始。这是getline函数和get函数不同之处。

## 文件输入输出

文件流是以外存文件为输入输出对象的数据流。输出文件流是从内存流向外存文件的数据,输入文件流是从外存文件流向内存的数据。每一个文件流都有一个内存缓冲区与之对应。
Expand Down Expand Up @@ -110,7 +101,7 @@ sstream 头文件定义了三个类型来支持`内存 IO`,这些类型可以

sstream 定义来的类型增加了一些成员来管理与流相关联的 string,可以对 stringstream 对象调用这些操作,但不能对其它 IO 调用。

* stringstream strm: 未绑定的stringstream 对象;
* stringstream strm: 未绑定的 stringstream 对象;
* stringstream strm(s):一个 stringstream 对象,保存了 string s 的一个拷贝;
* strm.str():返回 strm 所保存的 string 的拷贝;
* strm.str(s):将 string s拷贝到 strm 中,返回 void.
Expand Down Expand Up @@ -139,6 +130,25 @@ sstream 定义来的类型增加了一些成员来管理与流相关联的 strin

我们知道在要求使用基类对象的地方,可以使用继承类型的对象取代,所以在接受一个 iostream 类型引用或者指针参数的函数,可以用一个对应的 fstream(或 sstream)类型来调用。

## 相关函数

istream, ostream 类提供了许多函数,常用的有 get, getline 等。

`std::istream::get` 从输入流中读取一个字符,赋给字符变量ch,常用的原型为:

```c++
istream& get (char& c);
```
`std::istream::getline` 从输入流中读取字符,直到遇到终止符号,默认换行符为终止符号,读到换行符后,丢弃换行符(C++ 还提供一个功能类似的全局函数 std::getline)。常用的原型如下:
```c++
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
```

用getline函数从输入流读字符时,遇到终止标志字符时结束,指针移到该终止标志字符之后,下一个getline函数将从该终止标志的下一个字符开始接着读入。如果用cin.get函数从输入流读字符时,遇终止标志字符时停止读取,指针不向后移动,仍然停留在原位置,下一次读取时仍从该终止标志字符开始,这是getline函数和get函数不同之处。简单来说,**getline将丢弃换行符,而get()将换行符保留在输入序列里**,千万要注意 get 之后的换行符( **>> 操作符也不会丢弃换行符**,同样需要注意)。

# 输入输出缓冲区

有时候程序会出现奇怪的输出,或者输入中读取的数据和想象不一致,这通常是由于存在输出输入缓冲区导致的。
Expand Down Expand Up @@ -186,7 +196,7 @@ cin.ignore(a, ch)方法是从输入流(cin)中提取字符,提取的字符

不建议使用 `std::cin.sync()` 丢弃缓冲区内容,因为有的平台并不支持(OS X就不支持)。

## 一个陷阱
## 陷阱

`OJ 输入提前 break!!!`有时候会犯这类错误,且不容易察觉。

Expand All @@ -207,6 +217,29 @@ cin.ignore(a, ch)方法是从输入流(cin)中提取字符,提取的字符
cout << ans << endl;
}

读取操作时,`>> 操作符` 会跳过空白制表符,但是 getline 不会跳过。也就是说 getline 可能会读取 >> 操作后剩余下的换行符。假设一个输入流数据如下:

> 10 2
> name Jack
> name John
如果用下面的程序读取数据:

```c++
cin >> N >> M;
for(int i=0; i<2; i++){
cin.getline(names[i]);
}
```

那么读到的names数组前两项将会是 "", "name Jack"。因为 >> 读完 M 后还剩下一个换行符,将被 getline 读取到。解决办法就是在 第一句后面加上一句,**吃掉换行符**。(后面就不用吃掉换行符了,因为 getline 会丢弃换行符)

```c++
cin >> N >> M;
cin.get();
...
```

# 参考
C++ Primer 文件输入输出
[cplusplus: Clear Input Stream](http://www.cplusplus.com/forum/beginner/48568/)
Expand Down
87 changes: 85 additions & 2 deletions C++/Memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,20 +140,103 @@ malloc 的一个具体使用例子在 [gist](https://gist.github.com/xuelangZF/5

# 内存泄漏

内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

内存泄漏是最难发现的常见错误之一,因为除非用完内存或调用malloc失败,否则都不会导致任何问题。实际上,使用C/C++这类没有垃圾回收机制的语言时,很多时间都花在处理如何正确释放内存上。如果程序运行时间足够长,如后台进程运行在服务器上,只要服务器不宕机就一直运行,一个小小的失误也会对程序造成重大的影响,如造成某些关键服务失败。

C++中的内存泄露一般指`堆中的内存泄露`。堆内存是我们手动malloc/realloc/new申请的,程序不会自动回收,需要调用free或delete手动释放,否则就会造成内存泄露。内存泄露常见的原因大概有以下几种:

1. “无主”内存:申请内存后,指针指向内存的起始地址,若丢失或修改这个指针,那么申请的内存将丢失且没法释放。
2. 异常分支导致资源未释放:程序正常执行没有问题,但是如果遇到异常,正常执行的顺序或分支会被打断,得不到执行。所以在异常处理的代码中,要确保系统资源的释放。
3. 类的析构函数为非虚函数:析构函数为虚函数,利用多态来调用指针指向对象的析构函数,而不是基类的析构函数。

下面来看一个简单的内存泄漏示例代码:

```c++
void f(void) {
int *x = (int *)malloc(5 * sizeof(int));
int *y = new int[5];
// free(x);
// delete []y;
// x = NULL;
// y = NULL;
} // problem here: memory leak -- x, y not freed

int main(void) {
f();
return 0;
}
```
## 内存泄漏检测
内存泄露检测的关键在于记录分配内存和释放内存的操作,看看能不能匹配。跟踪每一块内存的声明周期,例如:每当申请一块内存后,把指向它的指针加入到List中,当释放时,再把对应的指针从List中删除,到程序最后检查List就可以知道有没有内存泄露了。
在一般的linux发行版中,有一个自带的工具可以很方便的替你完成这些事,这个工具就是mtrace。mtrace为内存分配、释放函数(malloc, realloc, memalign, free)安装hook函数,这些hook函数记录内存申请和释放的trace信息。
不过还有一款强大的检测工具 Valgrind,它是运行在Linux上一套基于仿真技术的程序调试和分析工具,包含一个内核——一个软件合成的CPU,和一系列的小工具,每个工具都可以完成一项任务──调试,分析,或测试等,其中Memcheck 工具可以用来方便的检测内存泄漏。
可以用下面命令检测程序是否发生内存泄漏:
```Bash
$ valgrind --leak-check=yes ./demo.o
```

对于下面的程序来说

```c++
#include <iostream>
using namespace std;

struct Node {
int val;
Node *next;
};


Node* still_reachable;
Node* possible_lost;

void show(){
Node *tmp = new Node; // definitely_lost
tmp->next = new Node; // indirectly_lost
}

int main()
{

show();
still_reachable = new Node;
possible_lost = new Node[2] + 1;
}
```
一共有四种类型的内存泄漏(关于这四种泄漏类型的详细内容,参考 [Memory leak detection](http://valgrind.org/docs/manual/mc-manual.html#mc-manual.leaks)):
```Bash
==45310== LEAK SUMMARY:
==45310== definitely lost: 16 bytes in 1 blocks
==45310== indirectly lost: 16 bytes in 1 blocks
==45310== possibly lost: 2,096 bytes in 2 blocks
==45310== still reachable: 16 bytes in 1 blocks
==45310== suppressed: 20,125 bytes in 189 blocks
==45310== Reachable blocks (those to which a pointer was found) are not shown.
```

# 更多阅读

[细说new与malloc的10点区别](http://www.cnblogs.com/QG-whz/p/5140930.html)
[Where are static variables stored (in C/C++)?](http://stackoverflow.com/questions/93039/where-are-static-variables-stored-in-c-c)
[Memory management in C: The heap and the stack](http://www.inf.udec.cl/~leo/teoX.pdf)
[Doc: Valgrind](http://valgrind.org/docs/manual/quick-start.html#quick-start.intro)
[缓冲区溢出详解](http://www.cnblogs.com/clover-toeic/p/3737011.html)
[缓冲区溢出攻击](http://www.cnblogs.com/fanzhidongyzby/p/3250405.html)
[缓冲区溢出攻击](http://www.cnblogs.com/fanzhidongyzby/p/3250405.html)
[C/C++内存泄漏及检测](http://blog.jobbole.com/95375/)
[Doc: Valgrind:Memory leak detection](http://valgrind.org/docs/manual/mc-manual.html#mc-manual.leaks)
[用valgrind检查C++程序的内存泄漏](http://zhiqiang.org/note/md/check-cpp-memory-with-valgrind.html)

[1]: http://7xrlu9.com1.z0.glb.clouddn.com/C++_Memory_1.jpg
[2]: http://7xrlu9.com1.z0.glb.clouddn.com/C++_Memory_2.jpg
[3]: http://7xrlu9.com1.z0.glb.clouddn.com/C++_Memory_3.jpg
[4]: http://7xrlu9.com1.z0.glb.clouddn.com/C++_Memory_4.png


3 changes: 2 additions & 1 deletion C++/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ C++11修复大量缺陷和降低代码拖沓,比如lambda表达式的支持将
[那些不能遗忘的知识点回顾——C/C++系列](http://www.cnblogs.com/webary/p/4754522.html)
[Can we change the value of a constant through pointers?](http://stackoverflow.com/questions/3801557/can-we-change-the-value-of-a-constant-through-pointers/3801601#3801601)
[C/C++内存泄漏及检测](http://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html)

[C++的坑真的多吗?](http://coolshell.cn/articles/7992.html)
[C++11 FAQ中文版](https://www.chenlq.net/cpp11-faq-chs)


0 comments on commit 32fd4b6

Please sign in to comment.