C++11新特性

auto

auto 的限制
前面介绍推导规则的时候我们说过,使用 auto 的时候必须对变量进行初始化,这是 auto 的限制之一。那么,除此以外,auto 还有哪些其它的限制呢?

  1. auto 不能在函数的参数中使用。
    这个应该很容易理解,我们在定义函数的时候只是对参数进行了声明,指明了参数的类型,但并没有给它赋值,只有在实际调用函数的时候才会给参数赋值;而 auto 要求必须对变量进行初始化,所以这是矛盾的。

  2. auto 不能作用于类的非静态成员变量(也就是没有 static 关键字修饰的成员变量)中。

  3. auto 关键字不能定义数组,比如下面的例子就是错误的:
    char url[] = “http://c.biancheng.net/”;
    auto str[] = url; //arr 为数组,所以不能使用 auto

  4. auto 不能作用于模板参数,请看下面的例子:
    template
    class A{
    //TODO:
    };
    int main(){
    A C1;
    A C2 = C1; //错误
    return 0;
    }

auto 用于泛型编程
auto 的另一个应用就是当我们不知道变量是什么类型,或者不希望指明具体类型的时候,比如泛型编程中。我们接着看例子:
template
void func(void){
auto val = T::get();
cout << val << endl;
}

c++的POD类型

最早看到POD(plain old data)类型,是在imperfect c++里。我觉得这是一本把我带到c++世界里的一本很重要的书。

书里是这样解释POD的:

1、 所有标量类型(基本类型和指针类型)、POD结构类型、POD联合类型、以及这几种类型的数组、const/volatile修饰的版
本都是POD类型。

2、 POD结构/联合类型:一个聚合体(包括class),它的非static成员都不是pointer to class member、
pointer to class member function、非POD结构、非POD联合,以及这些类型的数组、引用、const/
volatile修饰的版本;
并且,此聚合体不能有用户自定义的构造函数、析构函数、拷贝构造函数.

3、 POD类型可以具有static成员、成员typedef、嵌套struct/class定义和 成员函数/方法。

(C++标准)给出的定义:
将对象的各字节拷贝到一个字节数组中,然后再将它重新拷贝到原先的对象所占的存储区中,此时该对象应该具有它原来的值。

POD类型的特点:
所有POD类型都可以作为union的成员,反之,所有非POD类型都不能作为union的成员。
POD特性利用:
我们可以利用POD类型特性来判断一个类型是否为POD类型:

template struct must_be_pod
{
union
{
T noname;
};
};
这个模板的意思是,只要类型T是非POD类型,那么编译器将报错,因为T被作为了union的一个成员。

VS2008里的测试代码如下:
class A
{
public:
A(){}
void f() { cout << “A::F” << endl; }
protected:
private:
int i;
int j;
};
template struct must_be_pod
{
union
{
T noname;
};
};

must_be_pod a; 编译器会报错:1>member ‘must_be_pod::noname’ of union ‘must_be_pod::’ has user-defined constructor or non-trivial default constructor
其实POD本质就是与c兼容的数据类型

Lambda表达式

//详情
http://c.biancheng.net/view/7818.html

lambda匿名函数的定义
定义一个 lambda 匿名函数很简单,可以套用如下的语法格式:

[外部变量访问方式说明符] (参数) mutable noexcept/throw() -> 返回值类型
{
函数体;
};

在这里插入图片描述

C++ for循环

for (declaration : expression){
//循环体
}

int main() {
char arc[] = “abcde”;
vectormyvector(arc, arc + 5);
//for循环遍历并修改容器中各个字符的值
for (auto &ch : myvector) {
ch++;
}
//for循环遍历输出容器中各个字符
for (auto ch : myvector) {
cout << ch;
}
return 0;
}

declaration 参数既可以定义普通形式的变量,也可以定义引用形式的变量,应该如何选择呢?其实很简单,如果需要在遍历序列的过程中修改器内部元素的值,就必须定义引用形式的变量;反之,建议定义const &(常引用)形式的变量(避免了底层复制变量的过程,效率更高),也可以定义普通变量。

注意事项:

基于范围的 for 循环完成对容器的遍历,其底层也是借助容器的迭代器实现的。举个例子:
#include
#include
int main(void)
{
std::vectorarr = { 1, 2, 3, 4, 5 };
for (auto val : arr)
{
std::cout << val << std::endl;
arr.push_back(10); //向容器中添加元素
}
return 0;
}
程序执行结果可能为(输出结果不唯一):
1
-572662307
-572662307
4
5
可以看到,程序的执行结果并不是我们想要的。就是因为在 for 循环遍历 arr 容器的同时向该容器尾部添加了新的元素(对 arr 容器进行了扩增),致使遍历容器所使用的迭代器失效,整个遍历过程出现错误
如果读者想要彻底搞清楚程序执行失败的原因,读了解 vector 容器的底层存储机制,可阅读《C++ vector容器底层实现机制》一文。
因此,在使用基于范围的 for 循环遍历容器时,应避免在循环体中修改容器存储元素的个数。

C++11 const与constexpr

C++ 11标准中,为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,而将“常量”的语义划分给了新添加的 constexpr 关键字。因此 C++11 标准中,建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。
void dis_1(const int x){
//错误,x是只读的变量 x始终是个变量, 只是该变量只读., 故初始化数组时失败
array <int,x> myarr{1,2,3,4,5};
cout << myarr[1] << endl;
}

nullptr

总之在 C++11 标准下,相比 NULL 和 0,使用 nullptr 初始化空指针可以令我们编写的程序更加健壮。

unique_ptr

作为智能指针的一种,unique_ptr 指针自然也具备“在适当时机自动释放堆内存空间”的能力。和 shared_ptr 指针最大的不同之处在于,unique_ptr 指针指向的堆内存无法同其它 unique_ptr 共享,也就是说,每个 unique_ptr 指针都独自拥有对其所指堆内存空间的所有权
这也就意味着,每个 unique_ptr 指针指向的堆内存空间的引用计数,都只能为 1,一旦该 unique_ptr 指针放弃对所指堆内存空间的所有权,则该空间会被立即释放回收
考虑到不同实际场景的需要,unique_ptr 模板类提供了多个实用的构造函数,这里给读者列举了几种常用的构造 unique_ptr 智能指针的方式。

  1. 通过以下 2 种方式,可以创建出空的 unique_ptr 指针:
    std::unique_ptr p1();
    std::unique_ptr p2(nullptr);

  2. 创建 unique_ptr 指针的同时,也可以明确其指向。例如:
    std::unique_ptr p3(new int);
    由此就创建出了一个 p3 智能指针,其指向的是可容纳 1 个整数的堆存储空间。
    和可以用 make_shared() 模板函数初始化 shared_ptr 指针不同,C++11 标准中并没有为 unique_ptr 类型指针添加类似的模板函数。

  3. 基于 unique_ptr 类型指针不共享各自拥有的堆内存,因此 C++11 标准中的 unique_ptr 模板类没有提供拷贝构造函数,只提供了移动构造函数。例如:
    std::unique_ptr p4(new int);
    std::unique_ptr p5(p4);//错误,堆内存不共享
    std::unique_ptr p5(std::move(p4));//正确,调用移动构造函数
    值得一提的是,对于调用移动构造函数的 p4 和 p5 来说,p5 将获取 p4 所指堆空间的所有权,而 p4 将变成空指针(nullptr)。

  4. 默认情况下,unique_ptr 指针采用 std::default_delete 方法释放堆内存。当然,我们也可以自定义符合实际场景的释放规则。值得一提的是,和 shared_ptr 指针不同,为 unique_ptr 自定义释放规则,只能采用函数对象的方式。例如:
    //自定义的释放规则
    struct myDel
    {
    void operator()(int *p) {
    delete p;
    }
    };
    std::unique_ptr<int, myDel> p6(new int);
    //std::unique_ptr<int, myDel> p6(new int, myDel());

C++11 weak_ptr智能指针

http://c.biancheng.net/view/7918.html
,C++11标准虽然将 weak_ptr 定位为智能指针的一种,但该类型指针通常不单独使用(没有实际用处),只能和 shared_ptr 类型指针搭配使用。甚至于,我们可以将 weak_ptr 类型指针视为 shared_ptr 指针的一种辅助工具,借助 weak_ptr 类型指针, 我们可以获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、shared_ptr 指针指向的堆内存是否已经被释放等等。

需要注意的是,当 weak_ptr 类型指针的指向和某一 shared_ptr 指针相同时,weak_ptr 指针并不会使所指堆内存的引用计数加 1;同样,当 weak_ptr 指针被释放时,之前所指堆内存的引用计数也不会因此而减 1。也就是说,weak_ptr 类型指针并不会影响所指堆内存空间的引用计数。

除此之外,weak_ptr 模板类中没有重载 * 和 -> 运算符,这也就意味着,weak_ptr 类型指针只能访问所指的堆内存,而无法修改它

右值引用

一文读懂C++右值引用和std::move:
https://zhuanlan.zhihu.com/p/335994370

std::move语义:如果对象有移动构造,就优先调用移动构造,如果没有移动构造,就调用拷贝构造

std::move

https://ppipp.blog.csdn.net/article/details/84644069?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-8.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-8.control

移动构造函数

知乎:
https://www.zhihu.com/question/52138073

移动语义可以将资源(堆、系统对象等)通过浅拷贝方式从一个对象转移到另一个对象,这样能减少不必要的临时对象的创建、拷贝以及销毁,可以大幅度提高C++应用程序的性能,消除临时对象的维护(创建和销毁)对性能的影响

当我们定义了自己的拷贝构造,拷贝赋值运算符,析构函数后,编译器不会帮我们合成移动构造函数,因为,如果我们定义了这些操作往往表示类内含有指针成员需要动态分配内存,如果需要为类定义移动操作,那么应该确保移动后源对象是安全的,但是默认的移动构造函数不会帮我们把指针成员置空,移后源不是可析构的安全状态,如果这样,当离开移动构造后,源对象被析构,对象内的指针成员空间被回收,转移之后对象内的指针成员出现悬垂现象,程序将引起致命的错误。所以当我们定义了自己的拷贝操作和析构函数时,编译器是不会帮我们合成默认移动构造函数的

C++11-万能引用、引用折叠和完美转发

https://blog.csdn.net/itworld123/article/details/110914744

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值