0%

使用 cpp 中常用容器时,的注意事项。

不要保存 end 返回的迭代器

当我们添加或删除 vectorstring 的元素后,或在 deque 中首元素之外任何位置添加或删除元素后,原来 end 返回的迭代器总是会失效。因此,添加或删除元素的循环程序必须反复调用 end,而不能在循环之前保存 end 返回的迭代器,一直当做容器末尾使用。

std::map 遍历删除元素

对容器进行增、删元素操作,可能会使迭代器失效。关于这一点,复习 《C++ Primer》 P315

正确的写法:(只需要记住正确的写法,其他的即便不是错的也是不规范的)

C++11 标准下,使用 erase() 返回值更新迭代器:返回值 Iterator following the last removed element.

1
2
3
4
5
6
7
// erase all odd numbers from c
for(auto it = c.begin(); it != c.end(); ) {
if(it->first % 2 != 0)
it = c.erase(it);
else
++it;
}

C++11 之前,erase() 成员没有返回值。怎么遍历删除自行 Google 吧

阅读全文 »

在《Effective C++》条款 27 强调尽量少做转型动作,参考此条款中的内容整理笔记。

在 C++ 中转型是一个你会想带着极大尊重去亲近的一个特性。

我们先回顾转型的语法,然后回过头再看怎么赋予类型转型的能力。

隐式转型

我们经常接触的隐式转换发生于内置类型中的数值类型之间。但往往因为过于自然,反而忽略了转型动作的存在。

阅读全文 »

由生产者-消费者模式展开,学习其编程的最佳实践,却发现自己不知“信号量”的概念,忘了PV操作,困惑于“使用数组做循环队列时,判断满、空的条件怎么写”,为什么不直接使用 STL 的容器做队列?进出队列是不是严格需要锁?获取队列大小时是不是严格需要锁?

进程和线程管理

参考来源:C 语言中文网

进程控制块(PCB)

为了使参与并发执行的程序(含数据)能独立地运行,必须为之配置一个专门的数据结构,称为进程控制块(Process Control Block, PCB)。系统利用PCB来描述进程的基本情况和运行状态,进而控制和管理进程。相应地,由程序段、相关数据段和PCB三部分构成了进程映像(进程实体)。所谓创建进程,实质上是创建进程映像中的PCB;而撤销进程,实质上是撤销进程的PCB。值得注意的是,进程映像是静态的,进程则是动态的。

阅读全文 »

在学习 C++ 的时候经常见到“资源获取即初始化”这句话。一直困惑这句话要表达的意思,是强调“资源获取”还是强调“初始化”,字面意思:获得系统资源这个行为就是“初始化”。不理解到底是指什么。

维基百科怎么说?

我们看 RAII-Wikipedia 中的叙述:

RAII全称为Resource Acquisition Is Initialization,它是在一些面向对象语言中的一种惯用法。XX 在设计C++异常时,为解决资源管理时的异常安全性而使用了该用法。

RAII要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。

阅读全文 »

The Biggest Changes in C++11 (and Why You Should Care),译文:C++11 的重大改变

事实上,核心 C++11 已经有了很大的改变。C++11 标准库同样增加了新的内容。捎带一句,C++11, also formerly known as C++0x …

Core

事实上,核心 C++11 已经有了很大的改变。现在它支持 lambda 表达式,自动类型推断,统一的初始化语法,委托构造函数,已删除和默认函数声明,nullptr,以及最重要的,右值引用——一种预言将会改变创造和处理对象方法的技术。

Lambda 表达式

lambda 的函数调用运算符为 const-by-value,但对 mutable 关键字的使用可将其取消。

自动类型推断和 decltype

赋予 auto 关键词新生: 数据存储类型

auto 自动推导类型,轻度用户(不涉及模板)谨慎使用,在书写便利和代码易读两者之间寻求,滥用降低代码可读性。

注意使用的限制

1
2
3
4
5
6
size_t length = 10;
int diff = 0 - length;
auto diff2 = 0 - length;
// diff != diff2
cout << (0 - length) << endl;
// NOTE 并未像我们预期的那这样子输出 -10

统一初始化语法

列表初始化:初始化操作的多种变体是令人感觉困扰的重要原因之一。C++11 使用统一的大括号标记清除了这种混乱。

POD (程序设计) - wikipedia

看了以上几篇帖子之后,知道了几个名词:Aggregate 和 POD,trivial 和 standard-layout。但详细的概念很是混乱,其中一条条的“是与不是”、“有与没有”难道是让人用来背诵记忆的吗?实用主义不要求学究钻研,编码过程用到了再回来复习。目前,水过不学了。其实真要较真的话,应该直接去找 C++ 的新标准,网上的终究是个参考,会有出入。

删除和默认函数

  • 多看书,多写代码

nullptr

  • 在此之前是什么样子?会有什么问题?深度探索一下。

  • c++11 中的 nullptr 详解

  • NULL 和 0 - 蓝色的回答

    • 不推荐使用宏,甚至不承认宏。包括 NULL,C++标准是没有承认 NULL 是 null pointer constant 的。
    • 赋予 null pointer,应该是使用 0,而非 NULL

委托构造函数

右值引用

  • 区分“左值”和“右值”。引用自 右值引用 - wikipedia

    在C++11提出右值引用之前,C++03及更早的C++标准中,表达式的“值分类”(value categories)属性为左值或右值。左值是对应(refer to)内存中有确定存储地址的对象的表达式的值,而右值是所有不是左值的表达式的值。因而,右值可以是字面量、临时对象等表达式。能否被赋值不是区分C++左值与右值的依据。C++的const左值是不可赋值的;而作为临时对象的右值可能允许被赋值。左值与右值的根本区别在于是否允许取地址&运算符获得对应的内存地址

  • 移动语义?学习 C++ Prime

    • 移动构造函数、移动赋值运算符

      C++11 标准库大量使用了移动语义。许多算法和容器也为移动语义做了优化。

  • 【译】详解 C++ 右值引用,阅读笔记如下

    1. 概述中 # &foobar() 是取 foobar() 函数执行结果的地址,而不是函数指针,&foobar 才是函数指针。

    2. 右值引用,总算渐渐明朗了。但前提是分清左值/右值。

      const 常量是左值,还是右值呢?——左值,因为 const int max = 100; 中 max 是可以使用 & 取地址的。

    3. move语义# 中“当赋值操作符的右边是右值的时候,我们希望赋值操作符被定义成下面这样:”,醍醐灌顶啊

      此处的右值,在后续代码中可能会再次被用来给变量赋值吗?

      “move语义:当一个变量(a)作为拷贝构造函数或者赋值的来源时,这个变量要么就是以后都不会再使用,要么就是(使用时)作为赋值操作的目标(a = b)。”

      也就是,这个变量不能再用了。

      ——参考 右值引用是右值吗?#

      “move语义的重点在于将其应用于那些不重要的东西上面,那些move之后会马上销毁而不会被再次用到的东西上面。”

    4. 强制move语义# 中:

      C++11中的swap函数是这样的:…

      swap函数不能只做 a = std::move(b); 吗?

      值得注意的是对那些没有实现move语义的类型来说(没有针对右值引用重载拷贝构造函数和赋值操作符),新的swap仍然和旧的一样。

      可能只是为了兼容。参考 Debian8Light 代码验证。

    5. 右值引用是右值吗# 中读不懂:

      理论上来说goo()所引用的对象也可能在X x = goo();后被访问的到。但是回想一下,这种行为不正是我们想要的吗?我们也想随心所欲的在左值上面使用move语义。

    6. move语义与编译器优化# 暂时读不懂

    7. 完美转发相关内容暂时未看,涉及范型编程之泛型函数

Library

2003年,C++ 以库技术报告 1(TR1)的形式经历了一次大型重构。TR1 包含了新的容器类(unordered_setunordered_mapunordered_multisetunordered_multimap)和许多新的库,例如正则表达式,元组,函数对象包装器。随着 C++11 的颁布,TR1 连同新的库一起正式集成到 C++ 标准中。下面是 C++11 标准库的特性:

线程库

毫无疑问,从程序员角度看,C++11 最重要的改进就是并发。

新的智能指针类

C++98 只定义了一个智能指针类 auto_ptr,而这个类现在已经被废弃了。

C++11 包含了新的智能指针类:shared_ptrweak_ptr 和最近新加的 unique_ptr

weak_ptr 是多线程下,判断某一(在多个线程中共享的)对象是否 alive 的唯一方法。

新的算法

THE END

延伸阅读:

笔记针对以下问题:

  1. 在c语言中,sizeof运算符和strlen()函数有什么区别的?
  2. 如果/字符串/字符指针/用来存储汉字,对于这两者的计算结果有影响吗?
  3. 在C++中,sizeof运算符和strlen()函数的定位?
  4. 在C++中,string的lengt()size()
  5. 在C++中,string用来存储汉字时,……
阅读全文 »

在 C++ 中怎么去除字符串首尾的空格?怎么去掉字符串中所有的空格?

网上可以查到很多,有用 C 写的,有用纯 C++ 写的,混合的更是大有人在。功能都能实现,但哪个是最佳实践的?有以下几个标准 or 问题?

  • 代码足够简洁
  • 怎么保证效率?
  • 通用性:跨平台
  • 要不要考虑 C 调用问题?
阅读全文 »

2016/9/8 17:07:08

最近对于在类中使用的 static 有几个疑问,逐一列举并给出解惑。

问题一

问题一:我们都知道 C++ 类的静态成员变量在使用前必须要初始化。可是为什么一定要初始化呢?如果不初始化,为什么报 ld 链接错误?

先强调一点,其中的使用包括在类的成员函数中对静态成员变量的访问。

如果对于类的内存模型稍微理解那么一点点,这个问题其实很简单。

  1. 类的定义是在 POD 结构体的基础上进行了的升级,定义类本质上是对其普通成员变量(不包括静态成员变量)的封装,就是 C 中普通的结构体。

  2. 对于其静态成员变量,可以理解为在此结构体外声明的 C 语言静态变量,并且在结构体与静态此变量之间建立了某种映射关系(绑定)。

阅读全文 »

在项目开发中,非主体逻辑的部分在整体代码量中占得比重往往更大。比如我们做一个加减乘除计算器,需要处理用户输入非数字怎么办,数字太大溢出怎么办,零作为除数了怎么办等等;比如我们要读取配置文件中的用户名、密码,我们得首先处理配置文件不存在,内容格式不正确,用户名过长等等。

机器(具体说就是一门语言,比如 C++)是一板一眼的,你告诉它了它就能做,你没告诉的它就不知道。对机器来说不存在“常识”这个词。

用 C++ 写代码的时候总是避免不了处理错误,一般来说有两种方式:通过函数的返回值 return code;抛出异常 exceptions。

使用返回值的缺点

从 C 语言过渡过来的开发者可能更习惯使用返回值。就我自己的开发经历(给某个风场使用 Labwindows/CVI 开发自动化采集软件)来说,使用返回值有四点很是不爽的地方:

阅读全文 »