c++11-开发小技巧
前言
本文是记录个人对c++11新特性的学习,文中所用可能会采用其他大神的图、思路、例子等,请大神们见谅。本博客文章是在学习过程的一些总结,整理出来,分享给大家,希望对各位读者有帮助,文章中的总结可能存在很多不完整或有错误的地方,也希望读者指出。
1、类成员初始化列表
class A
{
public:
//在 C++11中可以使用大括号语法初始化数组类型的成员变量
A() : arr{0}
{
}
public:
int arr[4];
};
class A
{
public:
//C++ 11 在类定义处初始化成员变量
bool ma{true};
int mb{2019};
std::string mc{"helloworld"};
};
2、final、 override 关键字和 =default、 =delete 语法
class A final //防止类被继承
{
};
class B : A //报编译错误
{
};
override:显式标记表明该方法重写了父类的同名方法,加了该关键字后,编译器会在编译阶段做相应的检查,如果其父类不存在相同签名格式的类方法,编译器就会给出相应的错误提示。
//a.h
//使用=default 标记这类函数,则编译器会给出默认的实现
class A
{
public:
A() = default; //如果构造和析构中没有需要实现的内容,则加=default。
~A() = default;
};
//a.cpp
#include "a.h"
//在 cpp 文件中就不用再写 A 的构造函数和析构函数的实现了
class A
{
public:
A() = default;
~A() = default;
public:
A(const A& a) = delete;
A& operator =(const A& a) = delete; // 禁止编译器生成这些函数,实现防止这些类被拷贝
};
int main()
{
A a1;
//A a2(a1);
A a3;
//a3 = a1;
return 0;
}
//在 C++ 98/03 规范中, 如果我们想让一个类不能被拷贝(即不能调用其拷贝构造函数),则可以将其拷贝构造函数和 operator=函数定义成 private
3、STL中的emplace
emplace方便之处在于,可以用函数参数自动构造对象,而不是向vector的push_back,map的insert那样传入一个构造好的对象;
新引入的的三个成员emlace_front、empace 和 emplace_back,这些操作构造而不是拷贝元素到容器中,这些操作分别对应push_front、insert 和push_back,允许我们将元素放在容器头部、一个指定的位置和容器尾部
//C++11之前stl操作写法
std::vector<Point> vp;
std::map<std::string, Point> mp;
Point p(1, 2);
vp.push_back(p);
vp.push_back(Pointer(3, 4));
Point p1(10, 20);
mp.insert(std::pair<std::string, Point>("key1", p1));
Point p2(100, 200);
mp.insert(std::make_pair("key2", p2));
//C++11之后stl操作的写法
std::vector<Point> vp;
std::map<std::string, Point> mp;
vp.emplace_back(1, 2);
vp.emplace_back(3, 4);
Point p1(10, 20);
Point p2(100, 200);
mp.emplace("key1", p1);
mp.emplace("key2", p2);
与insert相比,省去了构造临时对象,减少了内存开销,但传递给emplace函数的参数必须与元素类型的构造函数相匹配。
4、using替换冗余的类型,尤其是std::function类型
class FuncFactory {
public:
void put_func(std::string, std::function<std::vector<std::string>(std::string)>);
std::function<std::vector<std::string>(std::string)> get_func(std::string);
private:
std::unordered_map<std::string, std::function<std::vector<std::string>(std::string)>> _func_map;
};
using func_t = std::function<std::vector<std::string>(std::string)>;
class FuncFactory {
public:
void put_func(std::string, func_t);
func_t get_func(std::string);
private:
std::unordered_map<std::string, func_t> _func_map;
};
5、头文件中使用#pragma once替换老破旧#ifndef #define #endif
pragma是基于头文件的文件路径来保持唯一的。而宏可以做到跨多个文件来保持include的唯一性。比如当你一个代码库中存在一个头文件的多个版本
6、用do while或IIFE跳过部分连续逻辑,但不结束函数
IIFE(Immediately Invoked Function Expression),即立即调用函数表达式
[]() {
// 步骤1
...
if (步骤1失败) {
return;
}
// 步骤2
...
if (步骤2失败) {
return;
}
// 步骤3
...
if (步骤3失败) {
return;
}
}();
// 步骤4
...
// 步骤5
...
普通 lambda表达式的末尾加上了一个括号,是让定义的lambda可以立即执行
7、函数直接返回STL容器或对象。不要返回指针,也不需要给函数加出参
std::vector<std::string> split(std::string str, std:string del) {
std::vector<std::string> str_list;
// ...
return str_list;
}