文章目录

  • 3.1.1 微小但重要的语法提升
    • Template 表达式内的空格
    • nullptr 和std::nullptr_t
  • 3.1.2 以auto 完成自动类型推导
  • 3.1.3 一致性初始化(Uniform Initialization) 与初值列(Initializer List)
  • 3.1.4 Range-Based for 循环
  • 3.1.5 Move 语义和Rvalue Reference
    • Rvalue和Lvalue Reference 的重载规则
    • 返回Rvalue Reference
  • 3.1.6 新式的字符串字面常量(String Literal)
    • Raw String Literal
  • 3.1.7 关键字noexcept
  • 3.1.8 关键字constexpr
  • 3.1.9 崭新的Template 特性
    • Variadic Template
    • Alias Template(带别名的模板,或者叫Template Typedef)
    • 其他的Template新特性
  • 3.1.10 Lambda
    • Lambda的语法
    • Capture(用以访问外部作用域)

3.1.1 微小但重要的语法提升

Template 表达式内的空格

“在两个template表达式的闭符之间放一个空格” 的要求已经过时了

vector<list<int> >;  //OK in each C++ version
vector<list<int>>;  // OK since C++11

上述两种形式都可以现在。

nullptr 和std::nullptr_t

C++11允许使用nullptr取代0或者NULL,用来表示一个pointer(指针)指向所谓的 no value (此不同于拥有一个不确定值) 。 这个新特性能帮助我们在“null pointer被解释为一个整数值” 时避免误解。

例如

void f(int);
void f(void *);f(0); // calls  f(int) f(NULL); // calls  f(int) if NULL is 0 ,ambiguous otherwisef(nullptr); // calls f(void*)

nullptr 是新关键字。它被自动转换为各种pointer类型,但不会被转换为任何整数类型。 它拥有类型std::nullptr_t ,定义于< cstddef>, 所以现在甚至可以重载函数令它们接受 null pinter. 注意, std:: nullptr_t 被视为一个基础类型。

3.1.2 以auto 完成自动类型推导

C++11 允许声明一个变量或对象(Object)而不需要指明其类型,只需要说它是auto 。例如

auto i =42; // i has type intdouble f(); // auto d=f();  // d has type double

以auto声明的变脸,其类型会根据其初值被自动推导出来,因此一定需要一个初始化操作:

auto i; //ERROR : can't deduce the type of i

可为它加上额外的限定符,例如

static auto vat =0.19;

如果类型很长或表达式很复杂,auto特别有用,例如


vector<stirng> v;auto pos = v.begin();  // pos has type vector<string> :: iteratorauto l = [] (int x) -> bool {  // l has the type of a lambda...,  //taking an int and returning a bool
};

上述末尾那个奇怪的东西是个对象,表示一个lambda。

3.1.3 一致性初始化(Uniform Initialization) 与初值列(Initializer List)

C++11引入了“一致性初始化(uniform initialization)”的概念, 意思是面对任何初始化动作,你可以使用相同语法,也就是使用大括号。以下皆成立:

int values [] {1,2,3};
std::vector<int> v{2,3,5,7,11,13,17};std::vector<std::string> cities{"Berlin","New York","London","Braunschweig","Cairo","Cologne"
};std::complex<double> c{4.0, 3.0 };  //equivalent to c(4.0 , 3.0)

初始列(initializer list) 会强迫造成所谓value initializaiton ,意思是即使某个local 变量属于某种基础类型(那通常是不明确的初值)也会被初始化为0(或者nullptr----如果它是个pointer的话):

int i //  i has undefined value
int j{}; // j is initialized by 0int* p; // p has undefined value
int* q{}; // q is initialized by nullptr

然而请注意,窄化(narrowing) -----也就是精度降低或造成数值变动----- 对大括号而言是不可成立的。例如:

int x1(5.3) ; // OK,but OUCH:x1 becomes 5
int x2 =5.3; // OK,but OUCH: x2 becomes 5int x3{5.0}; //ERROR:narrowing
int x4={5.3}; //ERROR :narrowingchar c1{7};  //OK:even though 7 is an int , this is not narrowingchar c2{99999};//  ERROR:narrowing(if 99999 doesn't fit into a char)std::vector<int> v1{1,2,4,5};  //OKstd::vector<int> v2{1,2.3, 4, 5.6}; // ERROR:narrowing doubles to ints

为了支持“用户自定义类型之初值列”的概念, C++11提供了class template std:: initializer_list<>,用来支持以一系列值(a list if values) 进行初始化,或在“你想要处理一系列值(a list of values)” 的任何地点进行初始化,例如:

void print( std::initializer_list<int> vals){for(auto p=vals.begin(); p!=vals.end();++p)std::cout<< *p <<<<endl;
}print({ 12, 3, 5, 7, 11, 13, 15}); //pass a list of values to print()

当“指明实参个数” 和“指明一个初值列” 的构造函数(ctor)同时存在,嗲有初值列的那个版本胜出:

class P
{public:P(int ,int );P(std:: initialier_list<int>);
};P p(77, 5);  //calls P::P(int,int )P q{77 , 5}; // calls P::P (intializer_list)P r{77,5,42};//calls P::P (intializer_list)P s={77,5};//calls P::P (intializer_list)

如果上述“带有1个初值列”的构造函数不存在,那么接受2个int的那个构造函数会被调用以初始化q和s,而r的初始化将无效。

由于初值列的关系,explicit之于“接受一个以上实参”的构造函数也会变得不一样。如今你可以令“多数值自动类型转换”不再起作用,即使初始化以=语法进行:

class P{public:P(int a,int b){...}explicit P(int a,int b,int c){...}};P x(77 , 5); //OK
P y{77,5};//OK
P  z {77,5,42}; //OK
P v={77,5};//OK(implicit type conversion allowed)
P w={77,5,42};// ERROR due to explicit(no implicit type conversion allowed)

同样地,explicit构造函数如果接受的是个初值列,会失去“初值列带有0个、1个或多个初值”的隐式转换能力。

void fp(const P&);fp({47,11});//OK,implicit conversion of{47,11} into P
fp({47,11,3});//ERROR due to explicit
fp(P{47,11});//OK,explicit conversion of {47,11}into P
fp(P{47,11,3}); //OK,explicit conversion of {47,11,3} into P

3.1.4 Range-Based for 循环

C++11 引入了一种崭新的for循环形式,可以逐一迭代某个给定的区间、数组、集合(range,array,or collection)内的每一个元素。 其他编程语言可能称此为foreach循环。其一般性语法如下:

for(decl:coll){statement
}

其中decl是给定的coll集合的每个元素的声明;针对这些元素,给定的statement会被执行。例如下面针对传入的初值列的每个元素,调用给定的语句,于是在标准输出装置cout输出元素值:

for( int i: {2,3,5,7,9,11,13,15}){std::cout<<i <<std::endl;
}

如果要将vector vec的每个元素elem乘以3,可以这么做:

std::vector<double> vec;
...
for( auto & elem: vec){elem*=3;
}

这里“声明elem为一个reference”很重要,若不这样做,for循环中的语句会作用在元素的一份local copy身上。

这意味着,为了避免调用每个元素的copy构造函数和析构函数,你通常应该声明当前元素为一个const reference。于是一个用来“打印某集合内所有元素”的泛型函数应该写成这样

template<typename T>
void printElements(const T& coll){for(const auto& elem:coll){std::cout<<elem<<std::endl;}
}

在这里,这种所谓range-based for 语句等同于:

{for(auto _pos=coll.begin(); _pos != coll.end();  ++_pos){const auto &elem =*_pos;std::cout<<elem<< std::endl;}
}

一般而言,如果coll提供成员函数begin()和end(),那么一个range-based for 循环声明为

for (decl: coll){statement
}

便等同于:

for( auto _pos=coll.begin(),_end=coll.end(); _pos!=_end; ++_pos){decl= *_pos;statement
}

或者如果不满足上述条件,那么也等同于一下使用一个全局性begin()和end()且两者都接受coll为实参:

{for(auto _pos=begin(coll),_end=end(coll); _pos!=_end;++_pos){decl=*_pos;statement}}

于是,你甚至可以针对初值列(initializer list)使用range-based for循环,因为class template std::initializer_list<>提供了成员函数begin()和end().

此外还有一条规则,允许你使用寻常的、大小已知的C-style array,例如:

int array[]={1, 2, 3, 4, 5};long sum=0; //process sum of all elementsfor(int x:array)sum+=x;for(auto elem: {sum,sum*2, sum*4})std::cout<< elem <<std::endl;

产生如下输出:

当元素在for循环中被初始化为decl,不得有任何显式类型转换(explicit type conversion) 。因此下面的代码无法通过编译:

class C{public:explicit C(const std::string& s);// explicit(!) type  conversion from strings
};std::vector<std::string> vs;
for(const C& elem:vs){ // ERROR,no conversion from string to C definedstd::cout<<elem<<std::endl;
}

3.1.5 Move 语义和Rvalue Reference

C++11的一个最重要的特性就是,支持move semantic(搬迁语义)。这项特性更进一步进入了C++11主要设计目标内,用以避免非必要拷贝(copy)和临时对象(temporary)。

这项新特性十分复杂,这里尽量给出一份简明扼要的介绍和摘要。

考虑以下代码

void createAndInsert(std::set<X>& coll){X x;// create an object of type Xcoll.insert(x); //insert it into the passed collection}

在这里我们将新对象插入集合(collection)中,后者提供了一个成员函数可为传入的元素建立一份内部拷贝(internal copy):

namespace std{template<typeneme T,..> class set{public:...insert(const T &v);// copy value of v};
}

这样的行为是有用的,因为集合(collection)提供value semantic 及安插“临时对象”(temporary object) 或“安插后会被使用或被改动的对象”的能力:

X x;
coll.insert(x); //inserts copy of xcoll.insert(x+x); //inserts copy of temporary rvaluecoll.insert(x); //insert copy of x (although x is not used any longer)

然而,对于后两次x安插动作,更好的是指出“被传入值(也就是x+x 的和以及x)不再被调用者使用”,如此一来coll内部就不需为它建立一份copy且“以某种方式move其内容进入新建元素中”。当x的复制成本高昂的时候—例如它是个巨大的string集合—这会带来巨大的效能提升。

自C++11开始,上述行为成为可能,然而程序员必须自行指明“move是可行的,除非被安插的那个临时对象还会被使用”。虽然编译器自身也有可能找出这个情况,允许程序员执行这项工作毕竟可使这个特性被用于逻辑上任何适当之处。先前的代码只需要简单改成这样:

X x;
coll.insert(x); //inserts copy of x(OK,x is still used)coll.insert(x+x); //moves(or copies) contents of temporary rvaluecoll.insert(std::move(x)); //moves(or copies) contents of x into coll

有了声明于< utility >的std::move() ,x可被moved而不再被copied 。然而,std::move() 自身并不做任何moving工作,它只是将其实参转成一个所谓的rvalue reference ,那是一种被声明为 X&&的类型。 这种新类型主张rvalue(不具名的临时对象只能出现在赋值操作的右侧)可被改动内容。 这份契约的含义是:这是个不再被需要的(临时)对象,所以你可以“偷”其内容和/或其资源。

现在,我们让集合提供一个insert()重载版本,用以处理这些rvalue reference:


namespace std{template<typename T,...> class set{public:...insert(const T& x); //for lvalues:copies the value...insert(T &&x); // for rvalues:moves the value...};}

我们可以优化这个针对rvalue reference 的重载版本,令它“偷取”x的内容。 为了这么做,需要type of x的帮助,因为只有type of x 拥有接近本质的机会和权利。 举个例子,你可以运用internal array 和pointer of x 来初始化被安插的元素。如果class x 本身是个复杂类型,原本你必须为它逐一复制元素,现在这么做则会带来巨大的效能改善。欲初始化新的内部元素,我们只需调用class X提供的一个所谓move构造函数,它“偷取”传入的实参值,初始化一个新元素。所有复杂类型都应该提供这样一个特殊构造函数 ----C++标准库也提供了-----永安里将一个既有元素的内容搬迁(move)到新元素中:

class X{public:X(const X& lvalue); //copy constructorX(X&& rvalue); //move constructor}

举个例子,string 的move构造函数只是将既有的内部字符数组(existing internal character array )赋予(assign)新对象,而非建立一个新arrry然后复制所有元素。 同样情况也适用于所有集合class:不再为所有元素建立一份拷贝,只需将内部内存(internal memory)赋予新对象就行。如果move构造函数不存在,copy构造函数就会被用上。

零位,你必须确保对于被传对象(其value被"偷取")的任何改动—特别是析构----都不至于冲击新对象(如今拥有value)的状态。因此,你往往必须清除被传入的实参的内容,例如将nullptr赋值给“指向了容器元素”的成员函数。

将“move semantic 被调用”的对象的内容清除掉,严格来说并非必要,但不这样做的话会造成整个机制几乎失去用途。事实上,一般而言,C++标准库的class保证了,在一次move之后,对象处于有效但不确定的状态。也就是说,你可以在move之后对它赋予新值,但当前值是不确定的。STL容器则保证了,被搬移内容者,搬移后其值为空。

同样地,任何nontrivial class都该同时提供一个copy assignment和一个move assignment 操作符:

class X{public:X& operator=(const X& lvalue); //copy assignment operatorX& operator=(X&& rvalue); // move assignment operator};

对于string和集合,上述操作符可以简单交换(swapping)内部内容和资源就好。然而你也应该清除*this 的内容,因为这个对象可能持有资源(如lock),因而最好很快释放它们。 再强调一次,move semantic 并不要求你那么做,但这是C++标准库容器所提供的一种优越质量。

最后,请注意两个相关议题:1)rvalue和lvalue reference 的重载规则;2)返回rvalue reference.

Rvalue和Lvalue Reference 的重载规则

Rvalue和lvalue的重载规则(overloading rule)如下:
如果你只实现 void foo(X&);而没有实现void foo(X&&); 行为如同C++98:foo() 可以lvalue但不能因rvalue被调用。

如果你实现void foo(const X&); 而没有实现void foo(X&&); 行为如同C++98:foo()可以lvalue也可因rvalue被调用。

如果你实现void foo(X&); void foo(X&&); 或void foo(const X&); void foo(X&&); 你可以区分“为rvalue服务”和“为lvalue服务”.为“rvalue服务”的版本被允许且应该提供move语义。也就是说,它可以“偷取”实参的内部状态和资源。

如果你实现void foo(X&&); 但既没有实现 void foo(X&);也没有实现void foo(const X&); ,foo()可因rvalue被调用,但当你尝试以lvalue调用它,会触发编译错误。 因此,这里只提供move语义。这项能力被程序库中诸如unique pointer ,file stream 或string stream 所用。

以上意味着,如果class未提供move语义,只提供惯常的copy构造函数和copy assignment 操作符,rvalue reference 可以调用它们。 因此std::move ()意味着"调用move语义(若有提供的话),否则调用copy语义"。

返回Rvalue Reference

你不需要也不应该move()返回值。C++ standard指出,对于以下代码

X foo(){X x;return x;
}

保证有以下行为:

  • 如果X有一个可取用的copy或move构造函数,编译器可以选择略去其中的copy版本。这也就是所谓的return value optimization(RVO),这个特性甚至在C++11之前就获得了大多数编译器的支持。
  • 否则,如果X有一个move构造函数,X就被moved(搬移)。
  • 否则,如果X有一个copy构造函数,X就被copied(复制).
  • 否则,报出一个编译期错误(compile-time error)。

也请注意,如果返回的是个Local nonstatic 对象,那么返回其rvalue reference 是不对的:

X&& foo(){X x;...return x;//ERROR:returns reference to nonexisting object
}

是的,rvalue reference 也是个reference ,如果返回它而它指向local对象,意味着你返回一个reference 却指向一个不再存在的对象。是否对它使用std::move()倒是无关紧要。

3.1.6 新式的字符串字面常量(String Literal)

自C++11起,你可以定义raw string 和multibyte/wide-character 等字符串字面常量。

Raw String Literal

Raw string允许我么能定义字符序列(character sequence),做法是确切写下其内容使其成为一个raw character sequence。于是你可以省下很多用来装饰特殊字符的escape符号。

Raw string 以R"(开头,以)" 结尾,可以内含line break。例如一个用来表示“两个反斜线和一个n”的寻常字面常量可定义如下:

"\\\\n"

也可定义它为如下raw string literal:

R"(\\n)"

如果要在raw string 内写出)”,可使用定义符(delimiter)。因此,一个raw string 的完整语法是R"delim(…)delim",其中delim是个字符序列,最多16个基本字符,不可含反斜线(backslash),空格(whitespace)和小括号(parenthesis)。

举个例子,下面的raw string literal

R"nc(a\b\nc()")nc";

等同于以下的寻常string literal:

“a\\\ n    b\\nc()\” \n   "

这样的string内含1个a、1个反斜线,一个新行字符(newline),若干空格,一个b,一个反斜线,一个n,一个c,一对小括号,一个双引号,一个新行字符,以及若干空格。

定义正则表达式时raw string literal 特别有用。

3.1.7 关键字noexcept

C++11提供了关键字noexcept,用来指明某个函数无法----或不打算----抛出异常。例如

void foo() noexcept;

声明了foo()不打算抛出异常。 若有异常未在foo()内被处理—亦即如果foo()抛出异常—程序会被终止,然后std::terminate()被调用并默认调用std::abort() 。

3.1.8 关键字constexpr

自C++11起,constexpr可用来让表达式核定于编译期。例如

constexpr int square(int x){return x*x;
}float a[square(9)]; //OK since C++11 :a has 81 elements

这个关键字修正了一个在C++98 使用数值极限时出现的问题,在C++11以前,以下式子

std::numeric_limits<short>::max()

无法被用作一个整型常量,虽然它在功能上等同于宏INT_MAX 。如今,在C++11中,这样一个式子被声明为constexpr,于是,举个例子,你可以用它声明array或进行编辑期运算(所谓metaprogramming):

std:;array<float,std::numeric_limits<short>::max()> a;

3.1.9 崭新的Template 特性

Variadic Template

自C++11开始,template可拥有那种“得以接受个数不定的template实参”的参数。 此能力称为variadic template 。举个例子,你可以写出这样的print(),得以在调用它时给予不定个数的实参且各具不同的类型:

void print(){}template <typename T,typename..Types>
void print(const T&firstArg, const Types&... args){std::cout<<firstArg<<std::endl; //print first argumentprint(args...); //call print() for remaining arguments
}

如果传入1或多个实参,上述的function template 就会被调用,它会把第一实参区分开来,允许第一实参被打印,然后递归调用print()并传入其余实参。你必须提供一个non-template重载函数print(),才能结束整个递归动作。

举个例子,如下调用:

print(7.5, "hello", std::bitset<16>(377),42);

会导致以下输出

7.5
hello
0000000101111001
42

注意,目前还在讨论以下例子是否也有效,原因是,正规而言,一个“单实参的variadic形式”与一个“单实参的nonvariadic形式”形成歧义;然而编译器通常接受这样的代码:

template <typename T>
void print(const T&arg){std::cout<<arg<<std::endl;
}template<typename T,typename ..Types>void print(const T& firstArg,const Types&... args){std::cout<<firstArg <<std::endl;//print first argumentprint(args...); //call print() for remaining arguments
}

在variadic template 内,sizeof…(args)会生成实参个数。

Class std:: tuple<> 大量使用了这一特性。

Alias Template(带别名的模板,或者叫Template Typedef)

自C++11 起,支持template(partial) type definition 。然而由于关键字typename 用于此处时总是出于某种原因而失败,所以这里引入关键字using ,并因此引入一个新术语alias template 。举个例子,写出如下代码

template<typename T>
using Vec=std::vector<T,MyAlloc<T>>;//standard vector using own allocator

之后,Vec< int > coll; 就等价于std::vector<int,MyAlloc< int>> coll;

其他的Template新特性

自C++11起,function template可拥有默认的template实参。此外,local type可被当作template实参。

3.1.10 Lambda

C++11引入了lambda,允许inline函数的定义式被用作一个参数,或是一个local对象。

Lambda改变了C++标准库的用法。

Lambda的语法

所谓lambda是一份功能定义式,可被定义于语句(statement)或表达式(expression)内部。因此你可以拿lambda当作inline函数使用。

最小型的lambda函数没有参数,什么也不做,如下:

[]{std::cout<< "hello lambda" <<std::endl;
}

可以直接调用它:

[]{std::cout<<"hello lambda" <<std::endl;
}(); //prints "hello lambda"

或者把它传递给对象,使之能被调用:

auto l=[]{std::cout<<"hello lambda"<<std::endl;};l(); //prints “hello lambda”

如你所见,lambda总是由一个所谓的lambda introducer引入:那是一组方括号,你可以在其内指明一个所谓的capture,用来在lambda内部访问”nonstatic外部对象“。如果无需访问外部数据,这组方括号可以为空。Static对象,诸如cout,是可被使用的。

在lambda introducer 和lambda body之间,你可以指明参数或mutable,或一份异常明细(exception specification)或attribute specifier以及返回类型。所有这一切都可有可无,但如果其中一个出现了,参数所需的小括号就必须出现。 因此lambda语法也可以是:
[…] {…}


[…] (…)

Lambda 可以拥有参数,指明于小括号内,就像任何函数一样:

auto l=[](const std::string& s){std::cout<<s<<std::endl;
};
l("hello lambda");

然而,请注意,lambda不可以是template,你始终必须指明所有类型。

lambda也可以返回某物。但你不需要指明返回类型,该类型会根据返回值被推导出来。例如下面的lambda的返回类型是int:

[]{return 42;
}

如果一定想指明一个返回类型,可使用新式C++语法

[]() -> double{return 42;
}

会返回42.0
这里指明返回类型,放在实参所需要的小括号以及 字符->以后

下面是一个lambda表达式的使用用例:

auto num=[](const int & n){return n;};auto n=num(2);cout<<n<<endl;

输出结果:2

Capture(用以访问外部作用域)

在lambda introducer(每个lambda最开始的方括号)内,你可以指明一个capture用来处理外部作用域内未被传递为实参的数据:

  • [=]意味着外部作用域以by value方式传递给lambda。因此当这个lambda被定义时,你可以读取所有可读数据,但不能改动它们。
  • [&]意味着外部作用域以 by reference 方式传递给lambda。因此当这个lambda被定义时,你对所有数据的涂写动作都是合法的,前提是你拥有涂写它们的权力。

也可以个别指明lambda之内你所访问的每一个对象是by value或 by reference。因此你可以对访问设限,也可以混合不同的访问权力。例如下面这些语句:

int x=0;
int y=42;
auto qqq=[x,&y]{cout<<"x: "<<x<<endl;cout<<"y: "<<y<<endl;++y;}
x=y=77;qqq();
qqq();cout<<"final y: "<<y<<endl;

输出结果

你也可以写[=,&y] 取代[x,&y],意思是以by reference 方式传递y,其他所有实参则以by value 方式传递。

为了获得passing by value 和passing by reference 混合体,你可以声明lambda为mutable。下例中的对象都以by value 方式传递,但在这个lambda 所定义的函数对象内,你有权利涂写传入的值。

例如

int id=0;
auto f=[id] () mutable{cout<<"id: "<<id<<endl;++id;};
id =42;
f();
f();
f();
cout<<id<<endl;

输出结果

可以把上述lambda的行为视同下面这个function object

class{private:int id;// copy of outside idpublic:void operator(){cout<<"id: "<<id<<endl;++id;}
};

由于mutable的缘故,operator()被定义为一个non-const成员函数,那意味着对id的涂写是可能的。 所以,有了mutable,lambda变得stateful,即使state是以 by value方式传递。 如果没有指明mutable(一般往往如此),operator()就成为一个const成员函数,那么对于对象你就只能读取,因为它们都是以值传递的。

C++11语言新特性-《C++标准库(第二版)》读书笔记相关推荐

  1. C++学习32:侯捷C++11,14新特性(标准库部分)

    文章目录 1 Rvalue references and Move Semantics 1.1 知识内容 1.2 move实战 2 新的容器 2.1 array 2.2 hashtable 2.3 f ...

  2. 标准模板库之容器-《C++标准库(第二版)》读书笔记

    写在前面:本文是阅读<C++标准库(第二版)>的读书笔记. 文章目录 6.1 STL组件(Component) 6.2 容器(Container) 6.2.1 序列式容器(Sequence ...

  3. STL容器之Deque-《C++标准库(第二版)》读书笔记

    写在前面:本文是阅读<C++标准库(第二版)>的读书笔记. 文章目录 7.4 Deque 7.4.1 Deque的能力 7.4.2 Deque的操作函数 7.4.3 Exception H ...

  4. 通用工具之Pair和Tuple-《C++标准库(第二版)》读书笔记

    写在前面:本文是阅读<C++标准库(第二版)>的读书笔记. 文章目录 5.1 Pair 和Tuple 5.1.1 Pair 元素访问 构造函数和赋值 逐块式构造 便捷函数make_pair ...

  5. C++标准库(第二版,作者_NicolaiMJosuttis)_第六章标准模板库_概述

    本文是一篇读书笔记,可以在偏向文字叙述方面让你了解STL,代码涉及到的不多,如果你明天面试,看看整个也许有点帮助,笔者就曾经被人问到:vector和list有什么区别?很遗憾当时我没有回答上来,现在的 ...

  6. C++标准库(第二版,作者_NicolaiMJosuttis)_第六章标准模板库_6.2.4关联式数组

    key/value pair 形式的集合也可以看作式一个关联式的数组,也即是索引并非整数的数组,因此这两个容器(map,unordered map)都提供了下标操作符[]. // STL_AssoAr ...

  7. C++标准库(第二版).pdf与STL源码剖析.pdf下载

    链接:https://pan.baidu.com/s/1KJjkz19AdFd_UHQzBwHd8A 提取码:2191 链接:https://pan.baidu.com/s/1754Oi4BdBE2s ...

  8. 从Folly源码学C++ 11的新特性

    两年前Facebook发布了他们的C++库,命名为Folly,这是一个在Facebook内部广泛和可重复使用的C++库组件大集合. 但很多成熟的C++开源库已经存在了,为什么又引进一个呢?除了这个库的 ...

  9. C++11 的新特性

    C++11 的新特性 1 变量和基本类型 1.1 long long 类型 扩展精度浮点数,10位有效数字 1.2 列表初始化 初始化的几种不同形式,其中用花括号来初始化变量称为列表初始化: 比如: ...

最新文章

  1. UNIX编程笔记:关于停止的进程接收信号的问题
  2. 自动化控制之线程池的使用
  3. e.getMessage 为空NULL
  4. Rhel5.6下构建在线邮件服务系统并实现不同网段不同域名间的邮件互发
  5. [回归分析][10]--相关误差的问题
  6. 【求助】windows server 2003 64位下面网卡IP总是默认为动态分派IP
  7. 如何确保您的Progressive Web App保持其Lighthouse审核分数
  8. Android屏幕大小和密度对照表,以及px、dip、sp等像素单位的解释
  9. 不用Oracle?基于MySQL数据库下亿级数据的分库分表
  10. bootstrap-table 列属性_Bootstrap Table 列参数columns使用总结
  11. npoi 未将对象引用设置到对象的实例_new一个对象到底占了多少内存?
  12. Node.js编写CLI的实践
  13. perl语言入门(7)
  14. mysql数据库计算全部女生_数据分析mysql入门到精通(1)
  15. scrollTop如何实现click后页面过渡滚动到顶部
  16. android地图搜索功能,[Android]百度地图POI检索
  17. 关于Linux内核学习
  18. .NetCore分布式部署中的DataProtection密钥安全性
  19. iis 值不在预期的范围错误解决办法
  20. 蜗蜗的毛衣花样c++

热门文章

  1. nodejs是用来做什么的?
  2. RX学习笔记:正则表达式
  3. MongoDB 2.5 版本将提供新的查询引擎
  4. maven+eclipse编译常见问题
  5. Name与x:Name的关系--转载
  6. BP神经网络分类2*2对角矩阵准确率数据汇总
  7. 【Paper】2012_Design of high performance multimedia control system for UAV/UGV based on SoC/FPGA Core
  8. 1.6 开发集和测试集的大小-深度学习第三课《结构化机器学习项目》-Stanford吴恩达教授
  9. DFTug - Running the Test DRC Debugger
  10. 【预告】新房装修网络规划网络布局学习笔记,家庭网络需求文章内容及结构...