现代C++ 教程:高速上手C++11/14/17/20. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 代码安全 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 出现的目的是为了替代 NULL。在某种意义上来说,传统 C++ 会把 NULL、0 视为同一种东 西,这取决于编译器如何定义 NULL,有些编译器会将 NULL 定义为 ((void*)0),有些则会直接将其定义 为 0。 C++ 不允许直接将 void * 隐式转换到其他类型。但如果编译器尝试把 NULL 定义为 ((void*)0), 那么在下面这句代码中: char *ch = NULL; 没有了 没有了 void * 隐式转换的 C++ 只好将 NULL 定义为 0。而这依然会产生新的问题,将 NULL 定义 成 0 将导致 C++ 中重载特性发生混乱。考虑下面这两个 foo 函数: void foo(char*); void foo(int); 那么 foo(NULL); 这个语句将会去调用 foo(int),从而导致代码违反直觉。 为了解决这个问题,C++11 引入了 nullptr0 码力 | 83 页 | 2.42 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 12 从计算机组成原理看 C 语言指针long 的大小应该和系统架构位数一样, 32 位系统上就 32 位, 64 位系统上就 64 位。 Windows 认为 long 不论 32 位系统还是 64 位系统都一样应该为 32 位,认为这样安全。 因此我们在编写 C 语言程序时,应该避免使用 long 类型,他会导致你的程序难以跨平台。 除了 long 之外的其他类型则没有区别,可以放心使用。 无符号整数: unsigned 修饰 有符号版本 他不需要手动 & 来创建。 • 他不需要手动 * 来创建。 • 他无法重新赋值,指向新的变量。 • 他无法为空指针。 C 语言指针:可以为空指针( NULL ) • 指针可以指向一个变量,也可以什么都不指向 ,也就是空指针,也就是 NULL 。 • 在右边的例子中,我们用空指针来表示“调用者 不需要 second 返回”。在 func 内还需要通过 if (psecond) 来判断是否为空。 *pars) ,这样只要 给 pars 传一个空指针,就表示“用户不想指定 这个参数”的意思。 C++ 可以用更安全的 func(std::optionalpars) 来替代。 NULL 的定义为什么是这样的? • 如果你看过标准库的头文件内容,会看到 NULL 的 本质无非是一个宏。那为什么要这样定义呢? • 可见他在 C++ 中会直接定义为常数 0 ,而 C 语言 0 码力 | 128 页 | 2.95 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 15 C++ 系列课:字符与字符串// 超级追求性能的极客 c_str 和 data 的区别 • const char * 可以隐式转换为 string (为了方便) • string 不可以隐式转换为 const char * (安全起见) • 如果确实需要从 string 转换为 const char * ,请调用 .c_str() 这个成员函数 。 字符串的连接( + 运算符) • C 语言规定,双引号包裹的字符串是 const 才行。 • 可以用 string(“hello”) 这种形式包裹住每个字符串常量,这样就方便用 + 了 。 • 初学者建议每个字符串都用 string(“...”) 这种形式写, C 语言字符串不安全。 • “hello” + “world” // 错误 • string(“hello”) + “world” // 正确 正确: C++14 新特性:自定义字面量后缀 • 不少同学就觉得这样好麻烦,其他语言都是直接 “ hello” 就是字符串类 型, C++ 还得套一层壳 string(“hello”) 才能变成安全封装的类型,才能用他 的成员函数。 • 因此, C++14 引入了一项缓解“键盘压力”的新特性: • 写 “ hello”_s 就相当于写 operator“”_s(“hello”, 5) ,就相当于0 码力 | 162 页 | 40.20 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 02 现代 C++ 入门:RAII 内存管理C++ 的 解构函数是显式的,离开作用域自动销毁,毫不含 糊(有好处也有坏处,对高性能计算而言利大于 弊) 如果没有解构函数,则每个带有返回的分 支都要手动释放所有之前的资源 : RAII :异常安全( exception-safe ) C++ 标准保证当异常发生时,会调用已创建对象的解构函数 。 因此 C++ 中没有(也不需要) finally 语句。 如果此处不关闭,则可等 待稍后垃圾回收时关闭。 14f) 不会出错,但是 int{3.14f} 会出错,因为 {} 是非强制转换。 2. Pig(“ 佩奇” , 3.14f) 不会出错,但是 Pig{“ 佩奇” , 3.14f} 会出错,原因同上,更安全。 3. 可读性: Pig(1, 2) 则 Pig 有可能是个函数, Pig{1, 2} 看起来更明确。 • 其实谷歌在其 Code Style 中也明确提出别再通过 () 调用构造函数,需要类型转换时应该 如果需要允许用户拷贝你的 Vector 类对象 ,我们还是需要实现一下的。 • 发现了吗?其实不管是 size/resize 这样的 get/set 模式也好;自定义的拷贝构造函数 也好; RAII 保证异常安全也好;都是在为 面向对象思想的“封装:不变性”服务。 • 即:保证任何单个操作前后,对象都是处于 正确的状态,从而避免程序读到错误数据 (如空悬指针)的情况。 三五法则:拷贝赋值函数 •0 码力 | 96 页 | 16.28 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 05 C++11 开始的多线程编程其实可以看做是为了支持多线程而 顺带引入的……如 chrono 、移动 、 lambda 、 RAII…… 第 0 章:时间 C 语言如何处理时间: time.h • long t0 = time(NULL); // 获取从 1970 年 1 月 1 日到当前时经过的秒数 • sleep(3); // 让程序休眠 3 秒 • long t1 = set_value() 不接受参数,仅仅作为同步用, 不传递任何实际的值。 第 3 章:互斥量 多线程打架案例 • 两个线程试图往同一个数组里推数据。 • 奔溃了!为什么? • vector 不是多线程安全( MT-safe )的容 器。 • 多个线程同时访问同一个 vector 会出现 数据竞争( data-race )现象。 std::mutex :上锁,防止多个线程同时进入某一代码段 • 里的 unlock() 永远得不到调用。 解决 1 : other 里不要再上锁 • 遇到这种情况最好是把 other 里的 lock() 去掉,并在其文档中说明:“ other 不是线 程安全的,调用本函数之前需要保证某 mutex 已经上锁。” 解决 2 :改用 std::recursive_mutex • 如果实在不能改的话,可以用 std::recursive_mutex0 码力 | 79 页 | 14.11 MB | 1 年前3
《深入浅出MFC》2/eManager,都像这样,是以消息为基础的事件驱 动系统。 可想而知,每一个Windows 程序都应该有一个回路如下: MSG msg; while (GetMessage(&msg, NULL, NULL, NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); } // 以上出现的函数都是Windows API 函数 消息,也就是上面出现的MSG InitInstance(hInstance, nCmdShow)) #0034 return (FALSE); #0035 #0036 while (GetMessage(&msg, NULL, 0, 0)) { #0037 TranslateMessage(&msg); #0038 DispatchMessage(&msg); #0039 } #0040 #0055 wc.hIcon = LoadIcon(hInstance, "jjhouricon"); #0056 wc.hCursor = LoadCursor(NULL, IDC_ARROW); #0057 wc.hbrBackground = GetStockObject(WHITE_BRUSH); // #0058 wc.lpszMenuName0 码力 | 1009 页 | 11.08 MB | 1 年前3
Hello 算法 1.1.0 C++ 版i; } return -1; } 值得说明的是,我们在实际中很少使用最佳时间复杂度,因为通常只有在很小概率下才能达到,可能会带来 一定的误导性。而最差时间复杂度更为实用,因为它给出了一个效率安全值,让我们可以放心地使用算法。 从上述示例可以看出,最差时间复杂度和最佳时间复杂度只出现于“特殊的数据分布”,这些情况的出现概率 可能很小,并不能真实地反映算法运行效率。相比之下,平均时间复杂度可以体现算法在随机输入数据下的 { if (nums[i] == target) return i; } return -1; } 7. 扩容数组 在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在 大多数编程语言中,数组的长度是不可变的。 如果我们希望扩容数组,则需重新建立一个更大的数组,然后把原数组元素依次复制到新数组。这是一个 ?(?) 的操作,在数组很大的情况下非常耗时。代码如下所示: 点的“值”和指向下一节 点的“引用”。 ‧ 链表的首个节点被称为“头节点”,最后一个节点被称为“尾节点”。 ‧ 尾节点指向的是“空”,它在 Java、C++ 和 Python 中分别被记为 null、nullptr 和 None 。 ‧ 在 C、C++、Go 和 Rust 等支持指针的语言中,上述“引用”应被替换为“指针”。 如以下代码所示,链表节点 ListNode 除了包含值,还需额0 码力 | 379 页 | 18.47 MB | 1 年前3
Hello 算法 1.0.0 C++版i; } return -1; } 值得说明的是,我们在实际中很少使用最佳时间复杂度,因为通常只有在很小概率下才能达到,可能会带来 一定的误导性。而最差时间复杂度更为实用,因为它给出了一个效率安全值,让我们可以放心地使用算法。 从上述示例可以看出,最差时间复杂度和最佳时间复杂度只出现于“特殊的数据分布”,这些情况的出现概率 可能很小,并不能真实地反映算法运行效率。相比之下,平均时间复杂度可以体现算法在随机输入数据下的 { if (nums[i] == target) return i; } return -1; } 7. 扩容数组 在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在 大多数编程语言中,数组的长度是不可变的。 如果我们希望扩容数组,则需重新建立一个更大的数组,然后把原数组元素依次复制到新数组。这是一个 ?(?) 的操作,在数组很大的情况下非常耗时。代码如下所示: 点的“值”和指向下一节 点的“引用”。 ‧ 链表的首个节点被称为“头节点”,最后一个节点被称为“尾节点”。 ‧ 尾节点指向的是“空”,它在 Java、C++ 和 Python 中分别被记为 null、nullptr 和 None 。 ‧ 在 C、C++、Go 和 Rust 等支持指针的语言中,上述“引用”应被替换为“指针”。 如以下代码所示,链表节点 ListNode 除了包含值,还需额0 码力 | 378 页 | 17.59 MB | 1 年前3
Hello 算法 1.2.0 简体中文 C++ 版i; } return -1; } 值得说明的是,我们在实际中很少使用最佳时间复杂度,因为通常只有在很小概率下才能达到,可能会带来 一定的误导性。而最差时间复杂度更为实用,因为它给出了一个效率安全值,让我们可以放心地使用算法。 从上述示例可以看出,最差时间复杂度和最佳时间复杂度只出现于“特殊的数据分布”,这些情况的出现概率 可能很小,并不能真实地反映算法运行效率。相比之下,平均时间复杂度可以体现算法在随机输入数据下的 { if (nums[i] == target) return i; } return -1; } 7. 扩容数组 在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在 大多数编程语言中,数组的长度是不可变的。 如果我们希望扩容数组,则需重新建立一个更大的数组,然后把原数组元素依次复制到新数组。这是一个 ?(?) 的操作,在数组很大的情况下非常耗时。代码如下所示: 点的“值”和指向下一节 点的“引用”。 ‧ 链表的首个节点被称为“头节点”,最后一个节点被称为“尾节点”。 ‧ 尾节点指向的是“空”,它在 Java、C++ 和 Python 中分别被记为 null、nullptr 和 None 。 ‧ 在 C、C++、Go 和 Rust 等支持指针的语言中,上述“引用”应被替换为“指针”。 如以下代码所示,链表节点 ListNode 除了包含值,还需额0 码力 | 379 页 | 18.48 MB | 10 月前3
Hello 算法 1.0.0b5 C++版i; } return -1; } 值得说明的是,我们在实际中很少使用最佳时间复杂度,因为通常只有在很小概率下才能达到,可能会带来 一定的误导性。而最差时间复杂度更为实用,因为它给出了一个效率安全值,让我们可以放心地使用算法。 从上述示例可以看出,最差或最佳时间复杂度只出现于“特殊的数据分布”,这些情况的出现概率可能很小, 并不能真实地反映算法运行效率。相比之下,平均时间复杂度可以体现算法在随机输入数据下的运行效率, { if (nums[i] == target) return i; } return -1; } 7. 扩容数组 在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在 大多数编程语言中,数组的长度是不可变的。 如果我们希望扩容数组,则需重新建立一个更大的数组,然后把原数组元素依次拷贝到新数组。这是一个 ?(?) 的操作,在数组很大的情况下是非常耗时的。 点的“值”和指向下一节 点的“引用”。 ‧ 链表的首个节点被称为“头节点”,最后一个节点被称为“尾节点”。 ‧ 尾节点指向的是“空”,它在 Java、C++ 和 Python 中分别被记为 null、nullptr 和 None 。 ‧ 在 C、C++、Go 和 Rust 等支持指针的语言中,上述的“引用”应被替换为“指针”。 如以下代码所示,链表节点 ListNode 除了包含值,还需0 码力 | 377 页 | 30.69 MB | 1 年前3
共 158 条
- 1
- 2
- 3
- 4
- 5
- 6
- 16













