锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 开源技术 / C++开源 / C++11全网最全归类引导
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

C++11全网最全归类引导


最近写了几篇C++11智能指针的文章,想对C++11的全部知识点有个全部学习,但是发现国内搜索的都是不全,国内突出了重点,不是最全,所以搜索国外了一篇文章进行C++11全网最全归类引导,记住是引导,不是每个知识点都展开讲。

介绍

本文旨在帮助经验丰富的C++用户理解和使用C++11中一些有趣的增强功能。我将讨论一些有趣的C++11功能,包括它们在 Visual Studio 11 Beta 和 g++ 中的可用性。

背景

需要非常好的 C++ 知识。在这里,我们只讨论新事物,这些事物大多是先进的。如果您不是专业的 C++ 开发人员,最好将本文留到以后。

揭幕

auto

auto 关键字允许从函数返回中推断变量的类型。这样,就不必显式指定类型。例如,以下代码:

int foo() { return 5; }  int j = foo();

可以写成:

int foo() { return 5; }   auto j = foo(); 

编译器会自动将 j 视为 int。

你可能会说大不了。事实并非如此。猜猜当你有一个 :typename::user::object::foodump::longlongyum::iterator

name::user::object::foodump::longlongyum::iterator foo() { return ... }
                       name::user::object::foodump::longlongyum::iterator j = foo();
                       for(name::user::object::foodump::longlongyum::iterator x = some.begin() ;
                         x < some.end() ; x++) { ... }

所有这些都非常无聊且容易出错。使用 auto 会让它变得相当简单和清晰:

name::user::object::foodump::longlongyum::iterator foo() { return ... }
   auto j = foo();  
 for(auto x = some.begin() ; x < some.end() ; x++) { ... }

我的评价:非常有帮助。 允许避免拼写错误。

>Visual C++ 11:可用。

G++:可用。

constexpr

constexpr 关键字允许您指定始终具有常量返回值的函数。考虑这个问题:

int foo() { return 15; }  int j[foo()];

编译器错误。编译器无法知道 foo() 返回值是否为 constant。

constexpr int foo() { return 15; }   int j[foo()];

编译器知道这将返回一个常量。foo()

我的评价:不确定。 constexpr函数可以执行的操作有很多限制,而且,实际上,int j[15]比int j[foo()]更干净。但是,可以提示编译器用编译时计算替换运行时计算 - 尽管我还没有找到实际示例。

Visual C++ 11: Not available.

G++: Available.

Explicit override,final,delete and default

这些修饰符允许您在成员函数中显式定义:

  • override 告诉编译器函数必须覆盖父类 function
  • final 告诉编译器函数不能被 descentant 类 functio 覆盖
  • default 指示编译器显式生成 default 构造函数
  • delete 告知编译器不得调用类的成员。

如果您想覆盖父函数,但不小心更改了函数签名,因此会生成第二个函数,则 override 很有用:

class a
    {    
public:
     virtual void foo(int) {...}
    };
  class b : public a
    {
     public:
     virtual void foo() override; // Compiler error. void foo() has not replaced void foo(int)
    }

在这里,程序员缩进来用b::foo()覆盖a::foo() ,但没有 override 指示,就会创建一个新的虚函数,因为程序员忘记了foo()原始函数将 int 作为参数。

如果您想确保函数永远不会被覆盖,final 非常有用:

class a
    {    public:
     virtual void foo(int) final
 {...} 
   }; 
 class b : public a 
   {     
public:
     virtual void foo(int) {}; // Compiler error. void foo(int) is final.
    }

default 允许程序员告诉编译器应该自动生成 default 构造函数,尽管可能还有其他构造函数:

class a     {    public:     a() = default;     a(int) { ... }    };

delete 允许程序员显式限制对成员的调用,例如由于不需要的强制转换或复制构造函数而被调用的函数:

class a
    {    public:
     a(const a&) = delete;
     void x(int) = delete;
     void x(float);
     };

在这里,类复制构造函数不能被调用,并且对a::x()的调用必须显式传递一个浮点数(例如,你不能调用x(0) )。

我的评价:有用。 它有助于避免不必要的错误。

Visual C++ 11:不可用。

extern 模板

模板中的关键字 extern 告诉编译器不要实例化模板:

template <typename X> class a
    {
    public:
     void test(X);
     };
  template class a<int>; // C++ 03 instantiation 
 extern template class a<int> // C++ 11 won't instantiate.

C++ 11 不会实例化 “a”,但 a 将对当前编译单元可见。

我的评价:有用。它有助于避免在多个 cpp 文件中出现不必要的实例化。

Visual C++ 11:不可用。

哈希表

C++ 11 具有无序的关联容器,称为哈希。这些容器使用哈希函数来存储元素。

void test_hash()
   	{
  	unordered_map<string,int> days(7);
  	const char* str[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  	for(int i = 0 ; i < 7 ; i++)
  	   days[str[i]] = i;
  	auto j = days["Wed"]; // j = 3;
  	}

我的评价:如果你需要它,很有用

Visual C++ 11:可用。

G++:可用。

初始值设定项列表

最后,C++ 中缺少了一样东西。使用 {} 初始化非 POD 对象的能力。例如,这有效:

int j[5] = {1,2,3,4,5};

但是这个,并没有:

vector<int> j = {1,2,3,4,5}; 

人们必须以一种麻烦的方式分配值,例如使用 for 循环。C++ 11 允许使用一个名为Ainitializer_list特殊模板,该模板可以通过 { } 获取其值,这可以用作任何函数、构造函数或非构造函数中的成员参数:

template <typename X>
 class A
  	{
  	public:
  		A(int x);
  		A(std::initializer_list<int> y);
  		void foo(std::initializer_list<X> list);
  	};
  A<int> a(5); // construct using A(int);
  A<float> b({1,2,3,4,5,6}); // construct using A(std::initializer_list<int> y);
  b.foo({0.5f,0.6f}); // call foo with parameters.

我的评价: 非常有用 .

Visual C++ 11::(不可用。

G++:可用。

Lambda 函数

lambda 函数是可以在另一个函数中使用的匿名函数。

语法:[capture][arguments]{body}(<call parameters>)

capture 是一个标识符列表,将在函数外部的主体(例如函数)中使用。如果标识符不在捕获列表中,则任何在 lambda 函数之外使用标识符的尝试都会生成编译器错误。

vector<int> flist(15);
  int sum = 0;
  for(int i= 0 ; i < 15 ;i++)
  	flist[i] = i;
  for(int i = 0 ; i < 15 ; [&sum](int x) { sum += x;}(flist[i++]));  // sum = 105.

[&sum](整数 x)} { 总和 += x;是 lambda 函数。它通过引用捕获 “sum” 外部变量,并将作为参数传递的 “x” 添加到其中。在 for 循环中,它立即用 flist[i] 调用。

您无需立即调用它:

auto f = [] (int x, int y) { return x + y; };  int j = f(5,6); // j = 11;  

我的评估:有用,但要小心,因为它很容易导致代码难以维护。

Visual C++ 11:可用。

G++:可用。

nullptr

nullptr 常量(类型 nullptr_t)允许您指定不得从零隐式转换的指针类型。

考虑这个问题:



int foo(int x) { ... } int foo(char* a) { ... } foo(NULL);

foo(NULL)调用将调用foo(int) , 而不是foo(char*) ,因为 NULL 定义为 0。

int foo(int x) { ... }
  int foo(char* a) { ... }
  foo(nullptr);

现在,foo(char*)将被调用。nullptr 可以隐式转换为任何其他指针类型,但不能转换为任何整型 int 类型(来自 bool 除外)。int j = nullptr 生成编译器错误。

我的评价:几乎没用。 你有同时接受整型和指针的重载函数是非常罕见的,如果有,你的设计中(通常)存在缺陷。

Visual C++ 11:可用。

G++:可用。

多态函数指针

这些类似于函数指针,不同之处在于它们允许隐式转换其参数。例如:

int foo(int x) { return x + 1;}
  typedef int (*foop)(short y);
  foop f = foo; // Error.
 It is int foo(int), not int foo(short);

使用多态指针可以完成此类转换:

std::function<bool (int)> foo;
  bool f2(short a) { ... }
  foo = f2; // Valid. short can be converted to int
  bool A = foo(5);

我的评价:如果你知道自己在做什么,那就有用了。C++ 是强类型的,弱化该功能可能会导致麻烦。

Visual C++ 11:不可用。

G++:可用。

正则表达式

您可能从 IRegExp 中了解的函数现在位于标准标头 <regex> 中:

char* str = "<h2>Header</h2>";
   regex rx("<h(.)>([^<]+)");
	  cmatch res;
  eegex_search(str, res, rx); // isolate "Header"

当然,正则表达式是一个独立的章节,我们不能在这里讨论。但很高兴将其视为标准。

我的评估:如果你需要正则表达式,这很有用

Visual C++ 11:可用。我确定他们使用的是旧的 VB 的 IRegExp ;)
G++: Available。

sizeof 成员

在 C++ 11 中,sizeof 可用于获取类成员的大小,而无需类实例:

class a
 {
     public     int b;
    };
  int x = sizeof(a::b); // Valid in C++ 11. In C++ 03 you had to have an instance of a class.

我的评估:必需。

Visual C++ 11:不可用。

静态断言

assert 关键字可以在运行时用于测试断言,#error 预处理器指令可以在预处理器中使用。new 关键字 static_assert 可用于编译器:

int j = 0;
  static_assert(j,"error!"); // Compiler error: compilation failed.

我的评价:可能有用,但不是很重要。

Visual C++ 11:可用。

G++:可用。

字符串

到目前为止,你可以使用 “string” 和 L“string” 分别使用普通字符串和宽字符串。C++ 11 添加了以下(非常有用的)文本:

  • u8“string” 来定义 UTF-8 字符串。
  • u“string” 用于 UTF-16 字符串。
  • U“string” 用于 UTF-32 字符串。
  • R“string” 表示原始字符串。

使用 R“string” 可以从源复制/粘贴字符串,而无需转义特殊字符,例如 \。

char* a1 = "Hello there, you can use the \ and / characters to pass arguments"; // Ugh, probably a bug, we forgot to escape \ 
 char* a2 = R"Hello there, you can use the \ and / characters to pass arguments"; // Fine.

我的评估:强制性,尤其是 R“string”。

Visual C++ 11:不可用。呃。

G++:可用。

强枚举

枚举不是类型化的,例如:

enum test {a = 0,b,c,d,e}; // implementation of the enum and it's size is compiler-dependant
  int j = e; // valid.
   bool h = d; // valid. 

现在可以键入它们:

enum class test: unsigned long {a = 0,b,c,d,e}; // implementation of the enum now is with unsigned long; Guaranteed size and type.
  int j = -1;
  if (j < test::c) //warning, comparing signed to unsigned. 

我的评价:很好。

Visual C++ 11:不可用。
G++:可用。

线程

线程类(包括互斥锁等同步内容)已添加到 C++ 11 中。

void test_thread_func(const char* message)
  	{
  	// Do something with parameter
  	}
  void test_thread()
  	{
  	thread t(bind(test_thread_func,"hi!"));
          t.join();
  	}

这将在单独的线程中启动 “test_thread_func” 并等待它完成 join() 函数。还有许多其他功能,如互斥锁、线程本地存储支持、原子操作等。

我的评价:很好,尽管对于严重的线程模型,您通常需要特定于操作系统的扩展。幸运的是,有一个 native_handle() 成员函数,它返回本机句柄(在 Win32 中为 HANDLE),因此您可以在没有C++替代方法时使用它。

Visual C++ 11:可用。
G++:不可用(至少我无法编译)。

Unique_Ptr 和更多智能指针

unique_ptr(C++ 11 中的新增功能)、shared_ptr 和 weak_ptr 可用。unique_ptr 以指针可以移动的方式扩展了 (现已弃用的) auto_ptr

unique_ptr<int> p1(new int(100));
  unique_ptr<int> p2 = move(p1); // Now p2 owns the pointer.
     p2.reset(); // memory is freed 
 p1.reset(); // does nothing.

我的评价:很好,尽管你不应该过分依赖自动指针来摆脱困境。使用分配器类来避免 new 和 delete 很好,但不要过度使用,因为在我看来,xxxx_ptr类已经太多了。不要落入依赖智能指针来增强设计较弱的应用程序的陷阱。

另外,请注意,许多人投票支持使用智能指针,以便在发生异常时可以安全地销毁内存,因此您可以继续而不会泄漏。记住异常应该是什么:您 99% 不应该正常继续的错误。不要使用 exceptions 而不是 if 或 switch。 不要对密码无效、找不到文件等错误引发异常。不要捕获 “not enough memory” 异常。您的代码已经存在缺陷,或者 Windows 非常不稳定!

Visual C++ 11:可用。

G++:可用。

不受限制的联合

不受限制的联合允许在哪些方面有更多的自由来决定什么是联合,什么不能:

class A
     {
     int b;
     int c;
     A() { b =5; c = 4;}
     };
  union B
     {
     int j;
      A a; // Invalid in C++ 03: A has a non trivial constructor. Valid in C++ 11:
     };

我的评价是:危险。 Union 主要为较低级别的功能实现,如 C 位调整、汇编内容等。他们应该受到非常严格的限制。

Visual C++ 11:不可用。

变量对齐

到目前为止,您可以使用特定于编译器的 #pragmas 来指定对齐方式。C++ 11 alows the alignas 关键字:

alignas(double) int d[8];  // d contains 8 integers, but it's size is enough to contain 8 doubles also.

此外,alignof 运算符返回标识符的对齐方式,例如 int j = alignof(d) 将返回 sizeof(double)。

我的评价:有用。

Visual C++ 11: 不可用
G++:不可用

可变参数模板

本文的最后一篇文章讨论了可变参数模板。这些是可以接受任何数字和任何类型的参数的模板:

template <typename ...T> void foo(T...args)

这允许对 printf 等函数进行类型安全的实现。下面的示例检查参数的大小,并使用适当的参数调用 func1():

void func1(int a1, int a2, int a3)
   { int j = a1 + a2 + a3;}
   template<class...T> int funcV(A...args)
   {
      	   int size = sizeof...(A);
   if (size == 0) func1(1,2,3);
   if (size == 1) func1(1,2,args...);
   if (size == 2) func1(1,args...);
   if (size == 3) func1(args...);
   }
  int main()
   {
   funcV(0);
   funcV(0,1,2);
   funcV(5,3);
   funcV("hello"); // error, func1 does not accept a char*. 
  }

由于 “args” 不容易被函数使用(因为它们的类型和大小未知),因此通常递归调用它们。

我的评价:有用,但它们真的很容易导致代码难以理解。请谨慎使用。

Visual C++ 11: 不可用

G++: 不可用

友情链接
版权所有 Copyright(c)2004-2024 锐英源软件
统一社会信用代码:91410105098562502G 豫ICP备08007559号 最佳分辨率 1440*900
地址:郑州市金水区文化路97号郑州大学北区院内南门附近