C++11常用特性(1)

1、关键字及新语法

1.1、auto关键字及用

auto关键字能做什么?

auto并没有让C++成为弱类型语言,也没有弱化变量什么,只是使用auto的时候,编译器根据上下文情况,确定auto变量的真正类型。

auto AddTest(int a, int b) 
{
    return a + b;
}

int main()
{
    auto index = 10;
    auto str = "abc";
    auto ret = AddTest(1,2);
    std::cout << "index:" << index << std::endl;
    std::cout << "str:" << str << std::endl;
    std::cout << "res:" << ret << std::endl;
}

是的,你没看错,代码也没错,auto在C++14中可以作为函数的返回值,因此auto AddTest(int a, int b)的定义是没问题的。

auto不能做什么?

auto作为函数返回值时,只能用于定义函数,不能用于声明函数。

#pragma once
class Test
{
public:
    auto TestWork(int a ,int b);
};

如下函数中,在引用头文件的调用TestWork函数是,编译无法通过。
但如果把实现写在头文件中,可以编译通过,因为编译器可以根据函数实现的返回值确定auto的真实类型。如果读者用过inline类成员函数,这个应该很容易明白,此特性与inline类成员函数类似。

#pragma once
class Test
{
public:
    auto TestWork(int a, int b)
    {
        return a + b;
    }
};

1.2、nullptr关键字及用法

为什么需要nullptr? NULL有什么毛病?

class Test
{
public:
    void TestWork(int index)
    {
        std::cout << "TestWork 1" << std::endl;
    }
    void TestWork(int * index)
    {
        std::cout << "TestWork 2" << std::endl;
    }
};

int main()
{
    Test test;
    test.TestWork(NULL);
    test.TestWork(nullptr);
}

NULL在c++里表示空指针,看到问题了吧,我们调用test.TestWork(NULL),其实期望是调用的是void TestWork(int * index),但结果调用了void TestWork(int index)。但使用nullptr的时候,我们能调用到正确的函数。

1.3、for循环语法

习惯C#或java的同学之前使用C++的时候曾吐槽C++ for循环没有想C#那样foreach的用法,是的,在C++11之前,标准C++是无法做到的。熟悉boost库读者可能知道boost里面有foreach的宏定义BOOST_FOREACH,但个人觉得看起并不是那么美观。
OK,我们直接以简单示例看看用法吧。

int main()
{
    int numbers[] = { 1,2,3,4,5 };
    std::cout << "numbers:" << std::endl;
    for (auto number : numbers)
    {
        std::cout << number << std::endl;
    }
}

以上用法不仅仅局限于数据,STL容器都同样适用。

2、STL容器

C++11在STL容器方面也有所增加,给人的感觉就是越来越完整,越来越丰富的感觉,可以让我们在不同场景下能选择跟具合适的容器,提高我们的效率.
本章节总结C++11新增的一些容器,以及对其实现做一些简单的解释。

2.1、std::array

个人觉得std::array跟数组并没有太大区别,对于多维数据使用std::array,个人反而有些不是很习
std::array相对于数组,增加了迭代器等函数(接口定义可参考C++官方文档)。


#include <array>
int main()
{
    std::array<int, 4> arrayDemo = { 1,2,3,4 };
    std::cout << "arrayDemo:" << std::endl;
    for (auto itor : arrayDemo)
    {
        std::cout << itor << std::endl;
    }
    int arrayDemoSize = sizeof(arrayDemo);
    std::cout << "arrayDemo size:" << arrayDemoSize << std::endl;
    return 0;
}

打印出来的size和直接使用数组定义结果是一样的。

2.2、std::forward_list

std::forward_list为从++新增的线性表,与list区别在于它是单向链表。我们在学习数据结构的时候都知道,链表在对数据进行插入和删除是比顺序存储的线性表有优势,因此在插入和删除操作频繁的应用场景中,使用list和forward_list比使用array、vector和deque效率要高很多。

#include <forward_list>
int main()
{
    std::forward_list<int> numbers = {1,2,3,4,5,4,4};
    std::cout << "numbers:" << std::endl;
    for (auto number : numbers)
    {
        std::cout << number << std::endl;
    }
    numbers.remove(4);
    std::cout << "numbers after remove:" << std::endl;
    for (auto number : numbers)
    {
        std::cout << number << std::endl;
    }
    return 0;
}

2.3、std::unordered_map

td::unordered_map与std::map用法基本差不多,但STL在内部实现上有很大不同,std::map使用的数据结构为二叉树,而std::unordered_map内部是哈希表的实现方式,哈希map理论上查找效率为O(1)。但在存储效率上,哈希map需要增加哈希表的内存开销。

#include <iostream>
#include <string>
#include <unordered_map>
int main()
{
    std::unordered_map<std::string, std::string> mymap =
    {
        { "house","maison" },
        { "apple","pomme" },
        { "tree","arbre" },
        { "book","livre" },
        { "door","porte" },
        { "grapefruit","pamplemousse" }
    };
    unsigned n = mymap.bucket_count();
    std::cout << "mymap has " << n << " buckets.\n";
    for (unsigned i = 0; i<n; ++i) 
    {
        std::cout << "bucket #" << i << " contains: ";
        for (auto it = mymap.begin(i); it != mymap.end(i); ++it)
            std::cout << "[" << it->first << ":" << it->second << "] ";
        std::cout << "\n";
    }
    return 0;
}

这里写图片描述
运行结果与官网给出的结果不一样。实验证明,不同编译器编译出来的结果不一样.
或许是因为使用的哈希算法不一样,个人没有深究此问题。

2.4、std::unordered_set

std::unordered_set的数据存储结构也是哈希表的方式结构,除此之外,std::unordered_set在插入时不会自动排序,这都是std::set表现不同的地方。

#include <iostream>
#include <string>
#include <unordered_set>
#include <set>
int main()
{
    std::unordered_set<int> unorder_set;
    unorder_set.insert(7);
    unorder_set.insert(5);
    unorder_set.insert(3);
    unorder_set.insert(4);
    unorder_set.insert(6);
    std::cout << "unorder_set:" << std::endl;
    for (auto itor : unorder_set)
    {
        std::cout << itor << std::endl;
    }

    std::set<int> set;
    set.insert(7);
    set.insert(5);
    set.insert(3);
    set.insert(4);
    set.insert(6);
    std::cout << "set:" << std::endl;
    for (auto itor : set)
    {
        std::cout << itor << std::endl;
    }
}

这里写图片描述

3、多线程

在C++11以前,C++的多线程编程均需依赖系统或第三方接口实现,一定程度上影响了代码的移植性。C++11中,引入了boost库中的多线程部分内容,形成C++标准,形成标准后的boost多线程编程部分接口基本没有变化,这样方便了以前使用boost接口开发的使用者切换使用C++标准接口,把容易把boost接口升级为C++接口。
我们通过如下几部分介绍C++11多线程方面的接口及使用方法。

3.1、std::thread

td::thread为C++11的线程类,使用方法和boost接口一样,非常方便,同时,C++11的std::thread解决了boost::thread中构成参数限制的问题,我想着都是得益于C++11的可变参数的设计风格。
我们通过如下代码熟悉下std::thread使用风格。

#include <thread>
void threadfun1()
{
    std::cout << "threadfun1 - 1\r\n" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "threadfun1 - 2" << std::endl;
}

void threadfun2(int iParam, std::string sParam)
{
    std::cout << "threadfun2 - 1" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "threadfun2 - 2" << std::endl;
}

int main()
{
    std::thread t1(threadfun1);
    std::thread t2(threadfun2, 10, "abc");
    t1.join();
    std::cout << "join" << std::endl;
    t2.detach();
    std::cout << "detach" << std::endl;
}

这里写图片描述
有以上输出结果可以得知,t1.join()会等待t1线程退出后才继续往下执行,t2.detach()并不会并不会把,detach字符输出后,主函数退出,threadfun2还未执行完成,但是在主线程退出后,t2的线程也被已经被强退出。

3.2、std::atomic

std::atomic为C++11分装的原子数据类型。

什么是原子数据类型?

从功能上看,简单地说,原子数据类型不会发生数据竞争,能直接用在多线程中而不必我们用户对其进行添加互斥资源锁的类型。从实现上,大家可以理解为这些原子类型内部自己加了锁。
我们下面通过一个测试例子说明原子类型std::atomic_int的特点。
下面例子中,我们使用10个线程,把std::atomic_int类型的变量iCount从100减到1。

#include <thread>
#include <atomic>
#include <stdio.h>
std::atomic_bool bIsReady = false;
std::atomic_int iCount = 100;
void threadfun1()
{
    if (!bIsReady) {
        std::this_thread::yield();
    }
    while (iCount > 0)
    {
        printf("iCount:%d\r\n", iCount--);
    }
}

int main()
{
    std::atomic_bool b;
    std::list<std::thread> lstThread;
    for (int i = 0; i < 10; ++i)
    {
        lstThread.push_back(std::thread(threadfun1));
    }
    for (auto& th : lstThread)
    {
        th.join();
    }
}

从没有小于等于0的情况,大家可以代码复制下来多运行几遍对比看看。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: C 11 新特性是指 C 语言的第 11 版本(也称为 C11),它引入了一些新的功能和改进,以提高 C 语言的使用性和性能。 首先,C 11 新特性中引入了线程支持。C 语言之前的版本没有原生的线程支持,但在 C11 中引入了线程库,使得开发者可以使用线程来并发执行不同的任务,从而提高程序的效率。 其次,C 11 新特性中还引入了原子操作。原子操作是指一种无法被中断的操作,它可以保证在多线程环境下的数据一致性和同步。C 11 提供了一些原子操作的函数和类型,使得开发者能够更方便地处理多线程编程中的共享数据和临界区问题。 此外,C 11 还引入了泛型选择表达式(Generic Selection Expression)。泛型选择表达式允许在编译时根据不同的类型执行不同的操作,这样可以提高代码的复用性和灵活性。开发者可以根据需要定义不同的操作和类型,然后在程序中使用泛型选择表达式来选择合适的操作。 最后,C 11 新特性还包括对 C 语言标准库的一些改进和增强。例如,C 11 引入了一些新的数学库函数、字符串处理函数、输入输出函数等,使得开发者能够更方便地进行数值计算、字符串处理和文件读写等操作。 综上所述,C 11 新特性为开发者提供了更强大和便捷的工具,使得 C 语言在并发编程、数据处理和算法实现方面具有更高的性能和灵活性。 ### 回答2: C 11中的新特性主要包括对C语言的增强和扩展,其中也包括了对PDF的支持。 首先,C 11对语言本身进行了改进。它提供了更丰富的数据类型支持,包括_Bool、_Imaginary和_Complex等新的数据类型,使得程序员能够更方便地处理复杂的数据。此外,C 11还引入了泛型选择表达式(Generic Selection Expression),使得代码能够更加灵活和通用。 其次,C 11还引入了对多线程编程的支持。它提供了线程库和原子操作函数,使得并发编程更加容易,能够充分利用多核处理器的计算能力,提高程序的性能。这对于需要处理大规模数据和实时计算的应用来说非常重要。 另外,C 11还加入了对PDF的支持。PDF(Portable Document Format)是一种常用的文档格式,C 11通过引入一些新的函数和数据类型,使得程序可以更方便地处理PDF文件。例如,C 11提供了一些用于读写PDF文件的函数接口,使得程序能够直接读取和修改PDF文件中的内容,实现对PDF文件的灵活处理。 总之,C 11的新特性不仅增强了C语言本身的功能和性能,还为开发者提供了更多的选择和便利,包括更丰富的数据类型支持、多线程编程和对PDF的处理。这些特性使得C 11成为一个更强大和适用的编程语言,在许多应用领域中得到了广泛的应用和推广。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值