Skip to content

Instantly share code, notes, and snippets.

@JeOam
Created June 14, 2018 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JeOam/f99f914046a373ec345c8175ffe3bb51 to your computer and use it in GitHub Desktop.
Save JeOam/f99f914046a373ec345c8175ffe3bb51 to your computer and use it in GitHub Desktop.
C++ Primer Notes
@JeOam
Copy link
Author

JeOam commented Jun 14, 2018

std::count << std::endl;

<< 为输出运算符
:: 为作用域运算符,表示其变量是定义在 std 的命名空间中。
std::countostream 对象
std::endl 为操纵符,效果是结束当前行,并将设备关联的缓冲区中的内容刷到设备中。

@JeOam
Copy link
Author

JeOam commented Jun 15, 2018

@JeOam
Copy link
Author

JeOam commented Jun 15, 2018

int ival = 42;

int &refVal = ival;
cout << refVal;  // 42

int *p = &ival;
cout << *p;      // 42

@JeOam
Copy link
Author

JeOam commented Jun 16, 2018

指针本身是一个对象,它又可以指向另外一个对象。因此指针本身是不是常量以及指针所指的是不是一个常量是两个相互独立的问题。

顶层 const(top-level const) 表示指针本身是个常量。
底层 const(low-level const)表示所指的对象是一个常量。

int i = 0;
int *const p1 = &i;  // 不能改变 p1 的值,这是一个顶层 const
const int ci = 42;   // 不能改变 c1 的值,这是一个顶层 const
const int *p2 = &ci;  // 允许改变 p2 的值,这是一个底层 const
const int *const p3 = p2; // 靠右的 const 是顶层 const,靠左的是底层 const
const int &r = cil   // 用于声明引用的 const 都是底层 const

@JeOam
Copy link
Author

JeOam commented Jun 16, 2018

类型别名(type alias):

typedef double wages;  // wages 是 double 的同义词
typedef wages base, *p;  // base 是 double 的同义词,p 是 double * 的同义词。

别名声明(alias declaration):

using SI = Sales_item;  // SI 是 Sales_item 的同义词。

@JeOam
Copy link
Author

JeOam commented Jun 16, 2018

auto 类型说明符: C++ 11 新标准引入了 auto 类型说明符,用它就能让编译器替我们去分析表达式所属的类型。auto 让编译器通过初始值来推算变量的类型。所以 auto 定义的变量必须有初始值。

使用 auto 也能在一条语句中声明多个变量。因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型都必须是一样的。

@JeOam
Copy link
Author

JeOam commented Jun 16, 2018

decltype 类型指示符:C++11 新标准引入,作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算它的值:

decltype ( f() ) sum = x;  // sum 的类型就是函数 f 的返回类型

@JeOam
Copy link
Author

JeOam commented Jun 20, 2018

头文件保护符(header guard):

#define 指令把一个名字设定为预处理变量,另外两个指令则分别检测某个指定的预处理是否已经定义:#ifdef 当且仅当变量为真,#ifndef 当且仅当不变量为定义为真。一旦检查结果为真,则执行后续操作直到遇到 #endif 指令为止。

@JeOam
Copy link
Author

JeOam commented Jun 24, 2018

#include <string>
using std::string;

int main()
{
  string s;  // 空字符串
  cin >> s;  
  cout << s << endl;
  return 0;
}

在执行读取操作时,string 对象会自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止。

string line;
getline(cin, line);  // 每次读入一整行,直至到达文件末尾 
line.size();  // 返回 string 对象的长度,注意这个 size 函数返回的是一个 string::size_type 类型的值。 

@JeOam
Copy link
Author

JeOam commented Jun 24, 2018

C 语言的头文件形如 name.h,C++ 则将这些文件命名为 cname。因此,诸如:cctype 头文件和 ctype.h 头文件的内容是一样的。

@JeOam
Copy link
Author

JeOam commented Jun 24, 2018

统计 string 对象中标点符号的个数:

string s("Hello World!!!");
decltype(s.size()) punct_cnt = 0;
for (auto c : s)
    if (ispunct(c))
        ++punct_cnt;
cout << punct_cnt; // get 3

for (auto &c : s)  // 对于 s 中的每个字符(注意:c 是引用)
    c = toupper(c);    // c 是一个引用,因此赋值语句将改变 s 中字符的值。
cout << s << endl;    // HELLO WORLD!!!

@JeOam
Copy link
Author

JeOam commented Jun 25, 2018

迭代器:
拥有 beginend 成员

  • begin 成员返回指向第一个元素(或第一个字符)的迭代器
  • end 成员返回容器(或 string 对象)"尾元素的下一位置(one past the end)" 的迭代器,该迭代器指示的是容器的一个本不存在的"尾后(off the end)"。这样的迭代器没什么实际含义,仅是个标记而已,表示我们已经处理完了容器的所有元素。特殊情况下如果容器为空,则 beginend 返回同一个迭代器。

** 标准容器迭代器的运算符 **

  • *iter 返回迭代器 iter 所指元素的引用
  • iter->mem 解引用 iter 并获取该元素的名为 mem 的成员,等价于 (*iter).mem
  • ++iter 令 iter 指示容器中的下一个元素
  • --iter 令 iter 指示容器中的上一个元素
  • iter1 == iter2 判断两个迭代器是否相等;如果两个迭代器指示的是同一个元素,或者他们是同一个容器的尾后迭代器,则相等;
  • iter1 != iter2

@JeOam
Copy link
Author

JeOam commented Jun 25, 2018

通过迭代器把 string 对象改成大写:

string s("some string");
for (auto it = s.begin(); it != s.end(); ++it)
    *it = toupper(*it)

@JeOam
Copy link
Author

JeOam commented Jun 26, 2018

assert 是一种预处理宏。它使用一个表达式作为它的条件:

#include <cassert>
assert(expr);

首先对 expr 求值,如果表达式为假,assert 输出信息并终止程序的执行。如果表达式为真,assert 什么都不做。

assert 的行为依赖于一个名为 NDEBUG 的预处理变量的状态。如果定义了 NDEBUG,则 assert 什么都不做。默认状态下没有定义 NDEBUG,此时 assert 将执行运行时检测。我们可以使用一个 #define 语句定义 NDEBUG,从而关闭调试状态。

@JeOam
Copy link
Author

JeOam commented Jun 27, 2018

程序调试时的变量:

  • __func__: 输出当前调试的函数的名字
  • __FILE__: 存放文件名的字符串字面值
  • __LINE__: 存放当前行号的整型字面值
  • __TIME__: 存放文件编译时间的字符串字面值
  • __DATE__: 存放文件编译日期的字符串字面值

@JeOam
Copy link
Author

JeOam commented Jun 27, 2018

使用 classstruct 定义类的唯一区别就是默认的访问权限。

  • 定义在 public 说明符之后的成员在整个程序内可被访问,public 成员定义类的接口
  • 定义在 private 说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问,private 部分封装了类的实现细节。

类可以允许其他类或函数访问它的非公有成员,方法是令其他类或者函数成为它的 友元friend)。如果类想把一个函数作为它的友元,只需要增加一条以 friend 关键词开始的函数声明语句即可。

@JeOam
Copy link
Author

JeOam commented Jun 28, 2018

一个 const 成员函数如果以引用的形式返回 *this,那么它的返回类型将是常量引用。

@JeOam
Copy link
Author

JeOam commented Jun 28, 2018

IO 对象无拷贝或赋值,进行 IO 操作的函数通用以引用的方式传递和返回流。

@JeOam
Copy link
Author

JeOam commented Jun 28, 2018

failbitbadbit 复位,但保持 eodbit 不变:

cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);
cout << unitbuf;  // 所以输出操作后,会立即刷新缓冲区,任何输出都立即刷新

cout << nounitbuf;  // 回到正常的缓冲方式

警告:如果程序崩溃,输出缓冲区不会被刷新。

@JeOam
Copy link
Author

JeOam commented Jul 5, 2018

@JeOam
Copy link
Author

JeOam commented Jul 13, 2018

一旦一个程序用光了它所有可用的内存,new 表达式就会失败。默认情况下,如果 new 不能分配所要求的内存空间,它会抛出一个类型为 bad_alloc 的异常。我们可以改变使用 new 的方式来阻止它抛出异常:

int *p1 = new int; // 如果分配失败,new  抛出 std::bad_alloc
int *p2 = new (nothrow) int; // 如果分配失败,new  返回一个空指针

bad_allocnothrow 都定义在头文件 new 中。

@JeOam
Copy link
Author

JeOam commented Jul 15, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment