`

C++11笔记一

 
阅读更多

一,C++11引入列表初始化来禁止缩窄(长度数据类型强转小长度类型引起的数据丢失)。可将用于初始化的变量或值放到大括号{}内:

int largeNum = 500000;
short anotherNum{largeNum }; // error! Amend types
int anotherNum{largeNum}; // OK!
float someFloat{largeNum}; // error! An int may be narrowed
float someFloat{500000}; //OK! 500000 can be accomodated

 

二,C++11引入了固定宽度的整形,能够以位为单位指定整数的宽度。这些类型为int8_t和uint8_t,分别用于存储8位的有符号和无符号整数。还可以使用16位、32位和64位整型,分别是int16_t、uint16_t、int32_t、uint32_t、int64_t和uint_64_t。要使用这些类型,比如包含头文件<cstdint>。

 

三,使用八进制或二进制字面常量赋值:

int someNumber = 012; // 八进制12赋值到十进制整型变量;
int someNumber = 0b1010; // 二进制1010赋值都十进制整型变量;

 

四,使用constexpr定义常量表达式:

    通过关键字constexpr可以让常量声明像函数:

constexpr double GetPI() {return 22.0/7;}

    在一个常量表达式中,可以使用另外一个常量表达式:

constexpr double TwicePI() {return 2*GetPI();}

    常量表达式看起来像函数,但在编译器和应用程序来看,它们提供了优化可能性。只要编译器能够从常量表达式中计算出常量,就可以在语句和表达式中对可使用常量的地方使用它。

    常量表达式必须包含简单的实现并返回简单的类型。如整型、双精度浮点数等。在C++14中,常量表达式可包含决策结构,如if和switch语句。

    使用constexpr并不一定能够保证会进行编译阶段优化,比如,使用常量表达式来计算用户输入数字的两倍,由于编译器无法计算这种表达式的结果,则可能会忽略constexpr,进而将常量表达式视为常规函数进行编译。

    可以使用constexpr来将类的构造函数定义为常量表达式,可能有助于提高性能:

class Sample
{
const char* someString;
public:
 constexpr Sample(const char* input)
  :someString(input)
 { // constructor code }
};

 

 

五,字符串结束字符'\0',它告诉编译器,字符串到此结束。这种C风格字符串是特殊的字符数组,因为总是在最后一个字符加上空字符'\0'。而在代码中使用字符串字面量时,编译器将负责在它后面添加'\0'。

    在数组中间插入'\0'并不会改变数组长度,而只会导致将该数组作为字符串处理时,将到这个位置结束。

    '\0'看起来像两个字符,但反斜杠是编译器能够理解的特殊转移编码,\0标识空,即它让编译插入空字符或零。不能将其写成'0',因为它标识字符0,其ASCII编码为48。

 

六,inline关键字

    在C/C++中,为了解决一些频繁调用小函数而大量消耗栈空间(栈内存)的问题,特别引入了inline修饰符,表示内联函数。栈空间就是指放置程序的局部数据(函数内数据)的空间。在系统下,栈空间是有限的,假如频繁大量使用就会造成栈空间不足而导致程序出错的问题。

#include <stdio.h>
//函数定义为inline即:内联函数
inline char* dbtest(int a) {
    return (i % 2 > 0) ? "奇" : "偶";
} 

int main()
{
   int i = 0;
   for (i=1; i < 100; i++) {
       printf("i:%d    奇偶性:%s /n", i, dbtest(i));    
   }
}

     上面的例子就是标准的内联函数用法,使用inline修饰带来的好处,我们表面上看不出来。其实,在内部的工作就是在每个for循环调用dbtest(i)的地方都换成(i % 2 > 0) ? "奇" : "偶",这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。

    1)inline使用限制:只适合函数内代码简单的函数使用,不能包含复杂的结构控制语句while/switch等,并且内联函数本身,不能是直接递归函数。

    2)inline仅是对编译器的建议,最后能否真正内联,看编译器的意思;

    3)linline函数的定义放在头文件中,因为内联函数要在调用点展开,编译器必须随处可见内联函数的定义。

    4)类中的成员函数与inline

          定义在类中的成员函数缺省是内联的,即在类定义时就给出函数定义。否则就不是内联的。

class A
{
    public:void Foo(int x, int y) {  } // 自动地成为内联函数
}

         如果成员函数的定义体不在类声明中,则需要单独声明:

// 头文件
class A
{
    public:
    void Foo(int x, int y);
}

 

// 定义文件
inline void A::Foo(int x, int y){}

         注意inline必须和定义体在一起才能声明为内联函数:

inline void Foo(int x, int y); // inline 仅与函数声明放在一起,不是内联函数

void Foo(int x, int y){}

 

void Foo(int x, int y);

inline void Foo(int x, int y) {} // inline 与函数定义体放在一起,是内联函数

     5)慎用inline:内联能提高函数的执行效率,但是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率,同时消耗更多的内存空间。以下情况不宜使用内联:

          a)如果函数体内的代码较长,使用内联将导致内存消耗代价较高;

          b)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。

     6)类的构造函数和析构函数容易让人误解呈使用内联函数更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行基类或成员对象的构造函数和析构函数,所以不要随便将构造函数和析构函数的定义体放在类声明中。

 

 七,lambda函数:

[optional parameters](parameter list) {statements;}

 

 八,组块分隔符:C++14新增,可提高代码可读性。

int moneyInBank=-70'000; // -70000
long populationChange = -85'000; // -85000
long long countryGDPChange = -70'000'000'000; // -70000000000
double pi = 3.141'592'653'59; // 3.14159265359

 

 九,指针声明:通常将指针声明为指向特定的类型,如int,意味着指针包含的地址对饮的内存单元,存储了一个整数。也可以将指针声明为一个内存块,这种指针被称为void指针。

PointedType *PointerVariableName;

    与大多数变量一样,除非对指针进行初始化,否则它包含的值将是随机的。如果不希望访问随机的内存地址,可将指针初始化为NULL。NULL是一个可以检查的值,且不会是内存地址:

PointedType *PointerVariableName = NULL; // initializing value

     使用引用运算符(&)获取变量的地址,如果varName是一个变量,&varName将是存储该变量的内存地址。可以使用指针来存储地址:

Type VariableName = InitialValue; // 声明一个变量
Type *Pointer = &Variable; // 声明一个该变量类型的指针,指向该变量的内存地址

    解除引用运算符(*)用于访问指针指向内存地址的数据。也叫间接运算符。

int age = 10;
int *p = &age; // p指向age的内存地址
cout << *p ; // 输出10
*p = 20;
cout << age; // 输出20
memset(&age, 5, 1);
cout << age; // 输出5
memset(p, 15, 1);
cout << age; // 输出15

 

十,关于sizeof():

    1)用于变量时,输出该变量类型的字节数长度;

    2)用于指针时,取决于编译器与操作系统。同一种指针的变量类型,不同操作系统下sizeof的长度不同。

    3)用于类/类对象时,指出类声明中所有数据属性占用的总内存量,单位为字节。可能会对某些属性进行填充,也可能不会,取决于编译器。但不考虑成员函数及其内部的局部变量。

    4)用于结构体时,指出结构体中所有数据属性占用的总内存量,单位为字节。

    5)用于共用体时,指出共用体最大成员的长度,即便该成员并不处于活动状态,单位为字节。

 

 十一,动态内存分配和释放

int myNum[100]; // 静态数组,不用手动释放,退出函数块时自动释放

     使用new和delete在自由存储区动态分配和释放内存:

Type *Pointer = new Type; // 分配内存
delete Pointer; // 释放内存

Type *Pointer = new Type[numElements]; // 分配内存块给数组
delete[] Pointer; // 释放内存

     不能将运算符delete用于任何包含地址的指针,而只能用于new返回的且未使用delete释放的指针。

 

十二、关键字const用于指针有三种方式:

    int* const p;不能修改指针地址,可以修改*p;

    const int* p; 不能修改*p,但可以修改指针地址;这种用得最多,避免指针传递时数据被意外修改。

    const int* const p;两则都不能修改。

//指针包含的地址是常量,不能修改,但可修改指针指向的数据:
int daysInMonth = 30;
int* const pDaysInMonth = &daysInMonth;
*pDaysInMonth = 31; // OK!Data pointed to can be changed
int daysInLunarMonth = 28;
pDaysInMonth = &daysInLunarMonth; // Not OK!Cannot change address!

//指针指向的数据为常量,不能修改,但可以修改指针包含的地址,即指针可以指向其他地方:
int hoursInDay = 24;
const int* pointsToInt = &hoursInDay;
int monthsInYear = 12;
pointsToInt = &monthsInYear; // OK!
*pointsToInt = 13; // Not OK!Cannot change data being pointed to
int* newPointer = pointsToInt; // Not OK!Cannot assign const to non-const

//指针包含的地址以及它指向的值都是常量,不能修改(这种组合最严格):
int hoursInDay = 24;
const int* const pHoursInDay = &hoursInDay;
*pHoursInDay = 25; // Not OK!Cannot change data being pointed to
int daysInMonth = 30;
pHoursInDay = &daysInMonth; // Not OK!Cannot change address

 

const char* str; // 与 const int i,没有区别 ,修饰 其所指向的 内存区域 是 只读的,不允许 修改
char * const str; // const 直接修饰 str,即指针变量本身,说明 该指针变量 本身是只读的,但是,其所指向的内存区域还是可以改变的。
char const* str; // 与声明1 本质一致
const char* const str; // 声明1 和声明 2 的 合并,其意义也是 2者的 合并
const char const* str; // 错误的声明。
 

 十三、动态内存分配失败:

    1、使用try-catch捕获std::bad_alloc异常:

try{
    int* pointsToManyNums = new int[0x1fffffff];
    delete[] pointsToManyNums;
}catch(std::bad_alloc) {
    cout << "error..";
}

     2,使用new的变种new(nothrow),分配失败不会引发异常,而返回NULL

int* pointsToManyNums = new(nothrow) int[0x1fffffff];
if(pointsToManyNums==NULL) {
    cout<<"error...";
}else {
    delete[] pointsToManyNums;
}

 

 十三,引用运算符(&),声明引用时需要将其初始化为一个变量,因此引用只是一种访问相应变量的存储数据的方式。

VarType original = Value;
VarType& ReferenceVariable = original;

     引用使得可以访问相应变量所在的内存单元,从而降低函数调用时参数传递引起的值拷贝,降低内存消耗。

#include "stdafx.h"
#include "windows.h" 
 
int add(int a) {
	return a + a;
}

void addPoint(int* a) {
	*a = *a + *a;
}

void addRef(int& a) {
	a = a + a;
}

void addPoint(int a, int* out) {
	*out = a + a;
}

void addRef(int a, int& out) {
	out = a + a;
}

int main()
{
	int num = 10; 
	printf("test add:%d\n", add(num)); // print 20

	int* point = &num;
	addPoint(point);
	printf("test addPoint:%d\n", *point); // print 20

	num = 10;
	int& ref = num;
	addRef(ref);
	printf("test addRef:%d\n", ref); // print 20

	int* out1 = new int;
	addPoint(10, out1);
	printf("test addRef:%d\n", *out1); // print 20
	delete out1;

	int ii1 = 0;
	int& out2 = ii1;
	addRef(10, out2);
	printf("test addRef:%d\n", out2); // print 20

	int* ii2 = new int;
	int& out3 = *ii2;
	addRef(10, *ii2);
	printf("test addRef:%d\n", *ii2); // print 20
	printf("test addRef:%d\n", out3); // print 20
	delete ii2; 

	system("pause");
    return 0;
}

     使用const关键字,可以禁止通过引用修改它指向变量的值。且const引用,只能赋值给const引用。

int original = 30;
const int& constRef = original;
constRef = 40; // Not allowed: constRef can't change value in original
int & ref2 = constRef; // Not allowed: ref2 is not const
const int& constRef2 = constRef; // OK

 

 

 

分享到:
评论

相关推荐

    C++学习笔记本

    C++学习笔记C++学习笔记C++学习笔记C++学习笔记C++学习笔记

    C++学习笔记.pdf

    C++学习笔记

    c++学习笔记精华版

    ### C++ 学习笔记精华版 #### 一、C++ 语言概述 **1、历史背景** - **C++ 的江湖地位** - Java、C、C++、Python、C# 是当前主流的编程语言之一,而 C++ 在这些语言中以其高效性和灵活性著称。 - **C++ 之父 ...

    c++学习笔记.pdf

    1. 关于C和C++语言的互调问题,extern "C"的作用至关重要。它确保了C++代码能够调用C语言编写的函数,而不会产生因为语言规范差异导致的编译错误。C++编译器在处理函数声明时会考虑函数签名(包括参数类型),而C...

    千锋C++笔记.zip

    《千锋C++笔记》是一份综合性的学习资料,涵盖了C++编程语言的基础到高级概念。这份笔记由知名教育机构“千锋”提供,旨在帮助初学者和有一定基础的程序员深入理解和掌握C++这一强大的系统级编程语言。下面将详细...

    C++ 学习笔记 整理

    6. **C++11及以后的新特性**:C++11引入了许多新特性,如auto关键字、右值引用、lambda表达式、智能指针等,C++14和C++17进一步增强了这些特性,使得C++更加现代化和高效。 7. **内存管理**:理解指针是学习C++的...

    达内C++课程笔记

    - C++11是C++的一个重要更新,引入了如右值引用、lambda表达式、auto类型推断、nullptr等新特性,提升了C++的现代性和易用性。 7. **STL(标准模板库)**: - STL是C++的标准库,包含容器(如vector、list、map等...

    自考C++笔记(上)

    "自考C++笔记(上)" 本笔记是作者全部手打创作的自考C++笔记,包含课本中例子的详细分析,共47200字,适合没有学过C语言的人认真学习和通过C++自考。 C++程序设计 ### 认识 C++的对象 #### 1.1 初识 ...

    c++学习笔记(个人学习时做的笔记)

    这份笔记主要涵盖了C++的基础知识,包括C++11和C++17的新特性,旨在帮助初学者理解C++的核心概念。 ### C++11特性 1. **引用(Reference)**:引用是一种别名机制,一旦引用被初始化为一个对象后,它就始终绑定到...

    黑马C++学习笔记

    "黑马C++学习笔记" 本笔记主要记录了C++的基础知识和一些重要的概念,包括变量的声明、赋值、输出、引用、指针、结构体等。 变量声明和赋值 在C++中,变量的声明和赋值是非常重要的。变量可以是整数、浮点数、...

    C++Primer读书笔记:C++概述.pdf

    C++Primer中文第三版(C++从入门到精通)第一章的读书笔记,主要是C++程序、预处理器指示符、iostream库等的基础知识点读书笔记。

    C++笔记.rar C++笔记.rar

    这份"C++笔记"包含了学习C++时的重要知识点和实践技巧。 1. **基础语法**:C++的基础包括变量、数据类型(如整型、浮点型、字符型等)、运算符(算术、比较、逻辑、位运算符等)、流程控制语句(如if-else、switch-...

    【C++学习笔记】一份详细的学习笔记,让你轻松掌握C++编程!

    【C++学习笔记】这份详尽的资源是为那些希望深入了解C++编程语言的人们精心准备的。C++是一种强大的、通用的编程语言,它的设计理念是面向对象,同时支持过程化编程,使得它在系统软件、应用软件、游戏开发、设备...

    effective c++读书笔记

    1. C++语言的联邦概念:C++是一个由多个次语言构成的语言联邦,这包括了C语言核心、面向对象的C++、模板C++以及标准模板库(STL)。这种理解对于深入学习C++至关重要。 - C语言核心:C++保留了C语言的语法,如区块...

    某课网C++笔记pdf

    对于C++而言,常见的开发工具之一便是Microsoft的Visual Studio系列。在本案例中提到的Visual Studio 2010旗舰版是一种较为成熟且功能全面的IDE。为了更好地提升编程体验,通常还会搭配使用一些插件或辅助工具,如...

    C++整理笔记word版——01 C++学习笔记

    1. **空头程序**:C++中的空头程序是一个没有实际操作的简单程序,通常用于测试编译环境。例如: ```cpp int main() { return 0; } ``` 2. **Hello World**:这是学习任何编程语言的第一步。在C++中,"Hello,...

    达内c++课程笔记

    【达内C++课程笔记】是一份全面涵盖了C++编程语言以及相关技术的教程资源,由达内科技提供。这份笔记不仅包含C++的基础知识,还深入探讨了C++的高级特性和实际应用,旨在帮助学习者从入门到精通,掌握C++编程技能。 ...

    c++源码笔记_非常值得一看

    1. 类与对象:C++的核心是面向对象编程,类是对象的蓝图,通过定义类可以封装数据和函数,实现数据隐藏和抽象。文件C++(day03).txt可能详细讲解了类的定义、构造函数、析构函数以及成员函数的使用。 2. 继承与多态...

    C++学习笔记.doc

    1. **变量和数据类型**:C++提供了多种数据类型,如int、float、char等,用于存储不同类型的数据。变量是存储数据的容器,每个变量都有特定的类型。 2. **运算符**:C++支持算术运算符(+、-、*、/、%)、关系...

    C++ 学习笔记002

    C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记002

Global site tag (gtag.js) - Google Analytics