c++新标准11~17等

系列文章目录



前言


一、fast view

列表初始化 std::initializer_list

{初始化列表},可用于所有的内置类型和用户定义的类型,可添加=也可不加。

eg:

int x = {5};  // = {3.4} 报错
double y = {2.35};
int *ar = new int[4] {2,3,4,5};

class UserDef
{
private:
  int roots;
  double w;
public:
  UserDef(int r, double ww): roots(r), w(w) {}
};
UserDef s1(1, 3.42);
UserDef s2{1, 3.45};
UserDef s2 = {1, 3.45};

如果有类将模板std::initializer_list作为参数的构造函数,则只有该构造函数可以使用列表初始化形式

STL容器提供了将initializer_list作为参数的构造函数

模板类initializer_list类包含begin(),end(), size()方法

#include <initializer_list>
template<class T>
T sum(std::initializer_list<T> il)
{
  T tot = 0;
  for (auto ite = il.begin(); ite != il.end(); ++ite){
    tot += *ite;
  }
  return tot;
}

int main()
{
  double total = sum({2.5, 3.1, 5.7});
}

auto

auto: http://c.biancheng.net/view/3718.html

int x = 0;
auto * a = &x;      // a -> int*,auto被推导为int
auto   b = &x;      // b -> int*,auto被推导为int*
auto & c = x;       // c -> int&,auto被推导为int
auto   d = c;       // d -> int ,auto被推导为int
const auto e = x;   // e -> const int
auto f = e;         // f -> int
const auto& g = x;  // g -> const int&
auto& h = g;        // h -> const int&

由上面的例子可以看出:

  • a 和 c 的推导结果是很显然的,auto 在编译时被替换为 int,因此 a 和 c 分别被推导为 int* 和 int&。
  • b 的推导结果说明,其实 auto 不声明为指针,也可以推导出指针类型。
  • d 的推导结果说明当表达式是一个引用类型时,auto 会把引用类型抛弃,直接推导成原始类型 int。
  • e 的推导结果说明,const auto 会在编译时被替换为 const int。
  • f 的推导结果说明,当表达式带有 const(实际上 volatile 也会得到同样的结果)属性时,auto 会把 const 属性抛弃掉,推导成 non-const 类型 int。
  • g、h 的推导说明,当 auto 和引用(换成指针在这里也将得到同样的结果)结合时,auto 的推导将保留表达式的 const 属性。

通过上面的一系列示例,可以得到下面这两条规则:

  • 当不声明为指针或引用时,auto 的推导结果和初始化表达式抛弃引用和 cv 限定符后类型一致。
  • 当声明为指针或引用时,auto 的推导结果将保持初始化表达式的 cv 属性。

注意 auto 是一个很强大的工具,但任何工具都有它的两面性。不加选择地随意使用 auto,会带来代码可读性和维护性的严重下降。因此,在使用 auto 的时候,一定要权衡好它带来的“价值”和相应的“损失”。

decltype

【C++深陷】之“decltype”

decltype的工作原理比auto负载,根据使用的表达式,指定的类型可以为引用和const

int j = 3;
int &k = j
const int &n = j;
decltype(n) i1;  // i1 type const int&  比auto更强大
decltype(j) i2;  // int
decltype( (j) ) i3; // int&
decltype(k+1)  i4; //int decltype并不会实际计算表达式的值,编译器分析表达式并得到它的类型

using

using itType = std::vector<std::string>::iterator; 同typedef

typedef 不行
template<typename T>
 using arr12 = std::array<T, 12>; // template for multiple aliases

智能指针

https://blog.csdn.net/surfaceyan/article/details/124449692

移动语义与右值引用

int ival = 4;
int&& ref = 5;  // 右值变左值
int&& refi= std::move(ival); // 左值变右值

移动语义,移动构造函数

Useless是一个string类,记录pc指针和n
还有一种只需要pc指针即可实现string的方式:

MyString 类 构造函数

#include <iostream>
using namespace std;

class Useless
{
private:
  int n;
  char* pc;
  static int ct;
  void ShowObject() const;
public:
  Useless();
  explicit Useless(int k);
  Useless(int k, char ch);
  Useless(const Useless& f);
  Useless(Useless && f);
  Useless operator+(const Useless& f) const;
  Useless& operator=(const Useless& f);
  Useless& operator=(Useless&& f);
  ~Useless();
  void ShowData() const;
};
// implementation
int Useless::ct = 0;
Useless::Useless()
{
  ++ct;
  n = 0;
  pc = nullptr;
  cout << "default constructor called; number of objects: " << ct << endl;
  ShowObject();
}
Useless::Useless(int k): n(k)
{
  ++ct;
  cout << "int constructor called; number of objects: " << ct << endl;
  pc = new char[n];
  ShowObject();
}
Useless::Useless(int k, char ch): n(k)
{
  ++ct;
  cout << "int, char constructor called; number of objects: " << ct << endl;
  pc = new char[n];
  for (int i = 0; i < n; ++i) {
    pc[i] = ch;
  }
  ShowObject();
}
Useless::Useless(const Useless& f): n(f.n)
{
  ++ct;
  cout << "copy const called; number of objects: " << ct << endl;
  pc = new char[n];
  for (int i=0; i < n; ++i) {
    pc[i] = f.pc[i];
  }
  ShowObject();
}
Useless::Useless(Useless&& f): n(f.n)
{
  ++ct;
  cout << "move constructor called; number of objects: " << ct << endl;
  pc = f.pc;
  f.pc = nullptr;
  f.n = 0;
  ShowObject();
}
Useless& Useless::operator=(const Useless& f)
{
  if (this == &f) {
    return *this;
  }
  delete[] pc;
  n = f.n;
  pc = new char[n];
  memcpy(pc, f.pc, n);  // string.h
  return *this;
}
Useless& Useless::operator=(Useless&& f)
{
  if (this == &f) {
    return *this;
  }
  delete[] pc;
  pc = f.pc;
  n = f.n;
  f.pc = nullptr;
  f.n = 0;
  return *this;
}
Useless::~Useless()
{
  cout << "destructor called; objects left: " << --ct << endl;
  cout << "deleted object:\n";
  ShowObject();
  delete[] pc;
}
Useless Useless::operator+(const Useless& f) const
{
  cout << "Entering operator+()\n";
  Useless tmp = Useless(n + f.n);
  for (int i=0; i<n; ++i) {
    tmp.pc[i] = pc[i];
  }
  for (int i=n; i<tmp.n; ++i) {
    tmp.pc[i] = f.pc[i-n];
  }
  cout << "tmp object:\n" << "Leaving operator+()\n";
  return tmp;
}
void Useless::ShowObject() const
{
  cout << "Number of elements: " << n;
  cout << " Data address: " << (void*)pc << endl;
}
void Useless::ShowData() const
{
  if (n == 0) {
    cout << "(object empty)";
  } else {
    for (int i=0; i<n; ++i) {
      cout << pc[i];
    }
  }
  cout << endl;
}


int main()
{
  {
    Useless one(10, 'x');
    Useless two = one;
    Useless three(20, 'o');
    Useless four(one + three);
    cout << "object one: ";
    one.ShowData();
    cout << "object two: ";
    two.ShowData();
    cout << "object three: ";
    three.ShowData();
    cout << "object four: ";
    four.ShowData();
  }
}

在linux下用g++进行编译得到的结果过:

实测没有调用移动构造,且只创建了4个对象。创建four时,该编译器没有调用任何构造函数:相反,它推断出对象four是operator+()所做工作的受益人,因此将operator+()创建的对象转移到four的名下。
实测将移动构造函数注释掉后程序输出结果不变

int, char constructor called; number of objects: 1
Number of elements: 10 Data address: 0x55e7d2a262c0
copy const called; number of objects: 2
Number of elements: 10 Data address: 0x55e7d2a262e0
int, char constructor called; number of objects: 3
Number of elements: 20 Data address: 0x55e7d2a26300
Entering operator+()
int constructor called; number of objects: 4
Number of elements: 30 Data address: 0x55e7d2a26320
tmp object:
Leaving operator+()
object one: xxxxxxxxxx
object two: xxxxxxxxxx
object three: oooooooooooooooooooo
object four: xxxxxxxxxxoooooooooooooooooooo
destructor called; objects left: 3
deleted object:
Number of elements: 30 Data address: 0x55e7d2a26320
destructor called; objects left: 2
deleted object:
Number of elements: 20 Data address: 0x55e7d2a26300
destructor called; objects left: 1
deleted object:
Number of elements: 10 Data address: 0x55e7d2a262e0
destructor called; objects left: 0
deleted object:
Number of elements: 10 Data address: 0x55e7d2a262c0

没有移动语义的老式编译器:
首先在operator+()内,调用构造函数创建tmp,并在01C337C4处给它分配了存储30个元素的空间。然后,调用拷贝构造创建临时对象(地址为01C337E8),f指向该副本。接下来,删除地址为01C337C4的对象tmp。然后,新建了对象four,它使用了01C337C4处刚刚释放的内存。接下来,删除了01C337E8处的临时参数对象。这表明,总共创建了三个对象,但其中的两个被删除。移动语义旨在消除这些额外的复制。

std::move强制移动

Useless one;
Useless two;
two = std::move(one);  // 将调用 Useless& operator=(Useless&&);

包装器

// ef代表可调用类型,如lambda,函数,重载了operator()()的对象
answer = ef(q);
template <class T, class T>
T use_f(T v, F f)
{
  return f(v);
}

#include <functional>
using fdd = std::function<double(double)>;

use_f(y, fdd(square));
use_f(y, fdd( Fq(3) ) );
...
template<class T>
T use_f(T v, std::function<T(T)> f)
{
  static int count = 0;
  count++;
  return f(v);
}

use_f<double>(y, square);
use_f<double>(y, Fq(3) );
...
参数dub、Fp(5.0)等本身的类型并不是function<double(double)>,因此在use_f后面使用了<double>来指出所需的具体化。T被设置为double,而std::function<T(T)>变成了std::function<double(double)>

可变参数模板

几个要点:

  • 模板参数包(parameter pack)
  • 函数参数包
  • 展开(unpack)参数包
  • 递归
// definition for 0 parameter
void show_list() {}
// definition for 1 parameter
template<typename T>
void show_list(const T& value)
{
    std::cout << value << "\n";
}
// definition for 2 or more parameters
template<typename T, typename ... Args>
void show_list(const T&value, const Args&... args)
{
    std::cout << value << ", ";
    show_list(args...);
}

chrono

using std::chrono::steady_clock;

chrono中分steady_clock和system_clock类

二、其他

线程库

regex
[ABcd]匹配单个字符
\d匹配单个数字

R"(字面值字符)"
R"任意符号(字面值字符)任意符号"

alignof() 运算符
说明符 alignas
constexpr

为嵌入式提供的便利
bitset

防御性编程
assert
static_assert

元编程指的是编写这样的程序,它创建或修改其他程序,甚至修改自身。

成员解除引用运算符

alignof
计算机系统可能限制数据在内存中的存储方式。例如,一个系统可能要求double值存储在编号为偶数的内存单元中,而另一个系统要求其起始地址为8个整数倍。运算符alignof将类型作为参数,并返回一个整数,指出要求的对齐方式。

noexcept

c++17

any

filesystem

atomic


总结

建议:
对内置类型以及stl使用 列表初始化 std::initializer_list
使用类内初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值