C++ 语言学习笔记2

  1. 字符串拼接问题

大量拼接字符串的效率从高到低依次为:+=、append()、stringstream、sprintf()。

常用的方法

  1. operator += 操作符
  2. append() 操作符
  3. reserve && operator +=
  4. stringstream 的用法

针对较短字符串,使用reserve提前分配空间对性能提升意义不大,当字符串的长度很长是,使用reserve方法提前分配空间可以带来比较大的性能提升。 operator+= 和 append 方法在进行字符串拼接时性能表现几乎一致。原因是stl 实现的operator+= 方式实际是直接调用了append 方法。 综上,拼接长字符串时最优方式是 reserve && append。

vector 中两个和内存相关的两个函数:

resize()函数和容器的size息息相关。调用resize(n)后,容器的size即为n。 reserve()函数和容器的capacity息息相关。reserve(n)预分配n个元素的存储空间。 从两个函数的用途可以发现,容器调用resize()函数后,所有的空间都已经初始化了,所以可以直接访问。 而reserve()函数预分配出的空间没有被初始化,所以不可访问。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    vector<int> a;
    a.reserve(100);
    a.resize(50);
    cout<<a.size()<<"  "<<a.capacity()<<endl;
    a.resize(150);
    cout<<a.size()<<"  "<<a.capacity()<<endl;
    a.reserve(50);
    cout<<a.size()<<"  "<<a.capacity()<<endl;
    a.resize(50);
    cout<<a.size()<<"  "<<a.capacity()<<endl;
    a.resize(210);
    cout<<a.size()<<"  "<<a.capacity()<<endl;

string中有两个函数:reserve()和resize(),和vector 中两个函数也是类似的。自动增长”的过程很耗时,并且会导致所有的指针、迭代器和引用失效。所以避免频繁的内存重新分配就显得很重要。

简单的实现 一直输入元素,如果是以"\n" 结尾,那么就跳出。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<vector>
#include<stdio.h>
using namespace  std;

const int N =1000010;

int main()
{
    int n;
    char ch;
    while(scanf("%d%c", &n, &ch))
    {
        cout<< n<< " ";
        if(ch =='\n') break;
    }
    return  0;
    
}

类型转换

C语言中有两种类型转换方式:(1). 隐性类型转换 (2). 显性类型转换。

隐式类型转化是编译器默默地、隐式地、偷偷地进行的类型转换,这种转换不需要程序员干预,会自动发生。 赋值转换

1
2
3
float f = 100;
int f = 100.1;
int n = f;

运算类型转换

1

下面的类型都是可以自动转换类型。 lSblUs.png

强制类型转换

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main() {
        int sum = 100;
        int count = 9;
        double average;
        average = (double)sum / count;
        printf("average is %lf\n", average);
        return 0;
}

C++ 中的类型转换风格

1
cast-name<type>(expression)

其中 type是转换的目标类型; expression 是被转换的值;cast-name有四种方式。

  • static_cast 静态类型转换
  • reinterpret_cast 重解析类型转换
  • dynamic_cast 动态类型转换
  • const_cast 去只读属性转换
1
static_cast<type>(expression)

任何编写程序时能够明确的类型转换都可以使用static_cast(static_cast不能转换掉底层const,volatile和__unaligned属性)。由于不提供运行时的检查,所以叫static_cast,因此,需要在编写程序时确认转换的安全性。

dynamic_cast转换仅适用于指针或引用。 相比static_cast,dynamic_cast会在运行时检查类型转换是否合法,具有一定的安全性。由于运行时的检查,所以会额外消耗一些性能。dynamic_cast使用场景与static相似,在类层次结构中使用时,上行转换和static_cast没有区别,都是安全的;下行转换时,dynamic_cast会检查转换的类型,相比static_cast更安全。 其它三种都是编译时完成的,dynamic_cast是运行时处理的,运行要进程类型检查.

const_cast用于移除类型的const、volatile和__unaligned属性。 常量指针被转换成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然引用原来的对象。

1
2
const char *pc;
char *p = const_cast<char*>(pc);

reinterpret_cast

1
reinterpret_cast<type>(expression)

非常激进的指针类型转换,在编译期完成,可以转换任何类型的指针,所以极不安全。非极端情况不要使用。

1
2
int *ip;
char *pc = reinterpret_cast<char*>(ip);

运算符的优先级

运算符优先级