美文网首页C++程序员
c++ primer 第五版学习笔记

c++ primer 第五版学习笔记

作者: David栗子 | 来源:发表于2017-12-11 16:46 被阅读46次

    第二章

    • 函数体外定义的内置类型变量会初始化为0,函数体外的是未初始化的
    • constexpr声明变量表示它是一个常量表达式(编译器可以确定的值),且只能应用于字面值
    • c++11中可以用using SI = Sales_item 来定义一个类型别名
    • top-level是指复合类型(指针、引用)对象本身是constlow-level是指复合类型所指的对象是const
    • delctype里对变量使用(),返回的推导类型永远是引用。比如
      int i;
      delctype((i)) d; // d是&int
      delctype(i) e; // e是int
      
    • c++11中,可以为在类的声明中直接给类的成员赋予默认值:
      class item
      {
      private:
          int data = 1;
      };
      

    第三章

    • vector可以用初始化列表来进行初始化vector<int> ivec{1,2,3};

      如果编译器无法用{}内的内容进行列表初始化,将会尝试用()的方式来进行初始化。
      
      ```vector<string> v8{10, "hi"}; // v8 has ten elements with value "hi"```
      
    • range for浏览容器时,不能改变容器的大小

    • c++11中加入了cbegincend来返回对应beginendconst迭代器

    • 列表初始化数组时,如果数组的维度大于列表中的元素个数,剩余元素会用默认值初始化

    • delctype作用于数组时,返回的也是数组本身的类型:

      decltype(ia) ia3 = {0,1,2,3,4,5,6,7,8,9};
      
    • c++11中可以用包含在头文件iterator中的beginend函数,对数组求得对应位置的指针:

      int ia[] = {0,1,2,3,4,5,6,7,8,9}; // ia is an array of ten ints
      int *beg = begin(ia); // pointer to the first element in ia
      int *last = end(ia); // pointer one past the last element in ia
      
    • 数组下标小于0时,按照0取值

    第四章

    • c++11中, m/n + m%n一定等于m,所以m%n的结果也可能是负的

    第五章

    • 新标准中,只要一个类型可以被move,就可以创建这种类型的容器
    • 不能把一个右值引用绑定到一个变量上,即使这个变量本身就是个右值引用
    • 不抛出异常的move的构造函数和赋值操作符应该标注为noexcept
    • 只有当一个类没有定义任何复制控制成员并且仅当所有成员数据都可以分别被move构造和赋值时,编译器才会为其合成move构造函数和赋值操作符
    • 定义了move构造函数和赋值操作符的类必须定义自己的复制操作,否则复制成员默认情况下会被删掉
    • 可以在成员函数的形参列表后加&&& 符号来限定this是左值引用或右值引用,如果同时是const的,则const在前
    • 如果一个成员函数有引用限定符,所有一样形参的重载版本成员函数必须都具有引用限定符。

    第六章

    • Initializer_list是一个标准库类型,可以用来在函数中传递可变个数的参数列表,也可以作为参数的返回值
    • 可以用下面的形式来定义函数返回类型:
      auto func(int i) -> int(*)[10];
      decltype(odd) *arrPtr(int i)
      
    • c++11里增加了constexpr函数,在声明前加constexpr即可。

    第七章

    • c++11中在成员函数声明或定义后加= default 代表让编译器生成其默认版本。
    • c++11中可以使用初始化列表给类成员添加默认值
      class Window_mgr {
      private:
          // Screens this Window_mgr is tracking
          // by default, a Window_mgr has one standard sized blank Screen
          std::vector<Screen> screens{Screen(24, 80, ' ') };
      };
      
    • c++11里可以使用代理构造函数
      class Sales_data {
      public:
          // nondelegating constructor initializes members from corresponding arguments
          Sales_data(std::string s, unsigned cnt, double price):
              bookNo(s), units_sold(cnt), revenue(cnt*price) {}
          // remaining constructors all delegate to another constructor
          Sales_data(): Sales_data("", 0, 0) {}
          Sales_data(std::string s): Sales_data(s, 0,0) {}
          Sales_data(std::istream &is): Sales_data() { read(is, *this); }
          // other members as before
      };
      

    c++11中有constexpr类,其必须提供至少一个constexpr构造函数

    第九章

    • emplace_front, emplace, emplace_back分别对应push_front, insert,push_back,用来在往容器中插入一个新构造的元素
    • 为了使操作在常量时间完成,forward_list没有insert,emplace,erase,而是定义了insert_after, emplace_after,erase_after以及before_begin.
    • 可以使用shrink_to_fit来尝试回收容器没有使用的内存,但并不保证
    • c++11增加了字符串和内置类型互转的接口:
      • to_string(val) 转为string
      • sto(s) 转为所代表的类型简写,比如i l ul ull f d ld等

    第十章

    • 标准库算法从不改变容器的大小
    • lambda表达式的基本形式:[capture list] (parameter list) -> return type { **function** body }
      • [&] [=] 分别表示lambda里使用的局部变量隐式地以引用和传值的形式被捕获。
      • [&, identifier_list] 表示identifier_list里的变量是传值捕获,其他变量以引用形式捕获
      • [=, reference_list] 表示reference_list里的变量是引用捕获,其他变量以传值形式捕获
      • 如果需要在lambda里修改以传值捕获的变量,需要在函数体前加上mutable
      • bind中使用ref(objcref(obj)可以将obj以普通引用或const引用的方式传递

    第十二章

    • 绝对不要用shared_ptrget接口来初始化或赋值给其他shared_ptr
    • 尽量不要把shared_ptr管理的资源以内置指针的形式暴露出来
    • 如果使用智能指针管理的资源不是new出来的,记得要给它传递一个deleter

    第十三章

    • 如果一个类需要析构函数,那么也几乎也确定需要复制构造函数和赋值操作符
    • c++11中可以在给类的复制控制函数和构造函数后加= default来让编译器生成一个默认版本。该函数是否内联取决于= default加在声明后还是定义后。
    • c++11中可以在类的复制控制函数和构造函数后加= delete来让编译器禁止生成其对应版本,它必须出现在声明之后。
    • 变量表达式本身是一个左值,例如:
      int &&rr1 = 42; // ok: literals are rvalues
      int &&rr2 = rr1; // error: the expression rr1 is an lvalue!
      
    • 被使用move的对象可以被赋值或析构,但不能继续使用它的值
    • 编译器仅为那些没有定义任何复制控制成员并且所有成员都可以被move的类合成move构造函数或move赋值操作符。
    • 当一个类满足一下几个条件之一时,编译器无法合成move控制函数:
      • 成员拥有复制控制函数却没有move控制函数
      • 有成员的move控制函数或是deleted或者不可访问的
      • 析构函数是deleted或者不可访问的
      • 有成员是const或者引用时
    • 一个类定义了move控制函数(构造、赋值)时,也应该定义复制控制函数,否则他们默认情况下会被定义为deleted
    • make_move_iterator函数接受一个普通迭代器,返回一个move迭代器。对move迭代器解引用产生一个右值引用。
    • 定义const成员函数时可以在参数列表后面加上&&&表明返回值的左/右值属性,需要跟在const之后(如果有的话)
    • 为一个类定义超过一个同名同参的成员函数时,要么全部提供引用限定符,要么一个也不提供。

    第十四章

    • c++11中的function类可以用来定义一个函数对象,例如:

      function<int(int, int)> f1 = add;

      定义了名为f1,返回类型为int,2个int参数的函数对象,调用函数为add函数。

    • c++11中类型转换函数可以加explicit关键字来表明只有显示调用,才可以产生类型转换。

    第十五章

    • c++11增加了override用来显式地表明此函数覆盖基类的虚函数
    • c++11中类名后加上final表明这个类不能作为基类,在成员函数后加表明子类不能覆盖它

    第十六章

    • c++11中可以用template<typename T> using twin = pair<T, T>;来为模版类型定义别名。

    • c++11中,模版类和模板函数都可以使用默认值

    • c++11中,可以使用extern template declaration; 来声明一个模版实例,这样可以减少编译器生成的模板实例。

    • 对于模板类型参数,只有const转换和数组或函数指针的转换会自动进行。对于非模板类型的参数,则进行正常的自动转换。

    • 类型别名或模版参数会导致引用的引用产生引用折叠,规则如下:

      X& &, X& &&, and X&& & all collapse to type X&

      X&& && collapses to X&&

    • c++11中,std::forward可以实现完美转发,即保留参数的左右值属性及const属性。

    • 假设有2个模板函数

      1. template<typename T> func(**const**  T &t) 
      2. template<typename T> func(**const** T* t)
      

    则对于一个const T* p的参数,编译器会优先调用第二个。因为第二个更specialized,第一个更general。

    • c++11中,结合可变参数模板加右值引用和std::forward实现可变参数完美转发:
      // an rvalue reference to a template parameter type
      template<typename... Args>
      void fun(Args&&... args) // expands Args as a list of rvalue references
      {
          // the argument to work expands both Args and args
          work(std::forward<Args>(args)...);
      }
      
    • 对于可变参数列表,可以使用某些格式使其展开。但展开后以逗号分隔的参数只能作为函数调用实参而不是逗号运算符。例子:
      template <typename T>
      void print(**const** T& t)
      {
          cout << t << " ";
      }
      
      template <typename ...Args>
      void varadic_print(Args&&... args)
      {
          int arr[]{(print(args), 0)...};
          cout << endl;
      }
      varadic_print(1, "abc", 2.0); //输出 1 abc 2
      

    第十七章

    • 输出流可以使用操作符showbase,显示整数时会加上0或0x
    • c++11里可以使用scientific操作符,使得实数以科学计数法表示
    • noskipws操作符可以使输入流读取空格

    第十八章

    • c++11中,可以于函数的声明或定义时最后跟上noexcept表明此函数不会抛出异常。也可以带一个bool参数,为false时表示可以抛出异常。
    • noexcept也可以作为一个表达式,返回作为参数传入的函数调用链中是否会抛出异常。
    • c++11中,可以在namespace声明前加inline,这样该namespace中的符号可以直接使用而不需要加上****namespace::
    • 可以用 namespace primer = cplusplus_primer; 这样的方式给命名空间cplusplus_primer起别名

    第十九章

    • c++11中增加了scoped枚举类型,在enum后面加structclass表明。例如:

      enum class peppers {red, yellow, green};

      这个枚举在使用时需要加上域名peppers,并且它不能自动转换为int类型。

    • c++11中,可以在枚举名后指定需要的表示类型:

      enum intValues : unsigned long long 
      {
          longTyp = 4294967295UL,
          long_longTyp = 18446744073709551615ULL
      }
      
    • c++11中加入了枚举类型的前向声明,需要指定名字和实现类型。

    • c++11中加入了mem_fn,与function用法类似,可以用来绑定类的成员函数。

    相关文章

      网友评论

        本文标题:c++ primer 第五版学习笔记

        本文链接:https://www.haomeiwen.com/subject/cdziixtx.html