当前位置: 代码迷 >> 综合 >> C++实践经验(二)
  详细解决方案

C++实践经验(二)

热度:78   发布时间:2024-02-20 13:01:09.0

18.调试与断言

常用调试宏

#include <assert.h>
cout << __FILE__ << endl;
cout << __LINE__ << endl;
cout << __TIME__ << endl;
cout << __FUNCTION__ <<endl;

静态断言static_assert()若不满足条件语句,则在编译时就报错,
assert()运行时报错

19.R与转义字符

在字符串前加上R可以避免缺失转义字符引起的各种稀奇古怪的现象

string path = R"E:\QtProjects\fplayer";

20.宽字符

wchar_t * p 的输出应该使用std::wcout减少出错概率

21.空指针的二义性:应使用nullptr初始化空指针

NULL是宏定义出来的,本质为int 0,因此把NULL当做空指针使用时会有二义性,比如:

void go(int); //函数1
void go(void*); //函数2
go(NULL); //会调用函数2,而不是函数1

22.auto与内部函数绑定

仿函数:一个函数指针,指向类内部公有函数

#include <functional>
using namespace std::placeholders
struct A{
    
int add(int);
int add2(int,int);
int add3(int,int,int);
}
A a;
auto func = bind(&A::add,&a,_1); 
auto func = bind(&A::add2,&a,_1,_2); 
auto func = bind(&A::add3,&a,_1,_2,_3); 

23.mutable突破const成员函数限定

使用mutable修饰成员变量,就可以在const成员函数中对该变量进行修改

24.std::function函数包装器

#include <functional>
void func(void);
class A{
    
public:int func(int){
    }
};
class B{
    
public:operator ()(int){
    }
};
std::function<void(void)> fptr1 = func;
fptr1();
std::function<int(int)> fptr2 = A::func;
fptr2(100);
B b;
fptr2 = b;
fptr2(100);

25.lambda表达式的工程意义和延迟加载细节

lambda表达式帮助c++实现了在需要的时候随时定义函数,就像在90c之前,c++无法随时定义变量,但90c之后可以,而现在有了lambda,c++可以随时定义函数

lambda表达式的延迟调用:

int a = 0;
auto fun1 = [=](){
    return a;};
auto fun2 = [&](){
    return a;};
a += 1;
cout << fun1() << endl; //输出0,实现了延迟调用
cout << fun2() << endl; //输出1,捕获的是引用
auto fun3 = [=](){
    return ++a;}; //报错,通过=捕获的变量只读
auto fun3 = [=]()mutable{
    return ++a;}; //想要修改可以添加mutable属性
cout << fun3() << endl; //输出2,成功自增

26.简易内存泄露检测设计

1.构建一个链表结构体_MemoryList用于保存每一次new的信息(size,FILE ,__LINE__等)
2.重载new,new[], delete,delete[],使得每次调用这些函数都会往_MemoryList中添加或者删除一个保存该次内存分配信息的节点
3.实现MemLeakDetec退出程序前调用,遍历_MemoryList,即可确认是否内存泄露,以及定位内存泄露的位置

27.对象构建的时间开销检测

#include <sys/time.h>
clock_t startTime = clock();
//content
clock_t elapsed = clock() - startTime; //单位CPU时钟

28.可变参数模板和singleton

参数类型后跟…

template<class... T>
void func(T... args){
    
cout << sizeof...(args) << endl; //打印参数个数
}
func();
func(1);
func(1,2.5,"");
template<typename T>
class Singleton{
    
public:template<typename... Args>static T* Instance(Args&&... args){
    //参数完美转发if(m_pInstance == nullptr){
    m_pInstance = new T(std::forward<Args>args...);//参数完美转发}return m_pInstance;}
private:Singleton(void){
    }Singleton(const Singleton&){
    }Singleton& operator =(const Singleton&){
    }
private:static T* m_pInstance;
};
struct CLASSA{
    CLASSA(){
    cout<<"class A"<<endl;}
};
struct CLASSB{
    CLASSB(int x){
    cout<<"classB"<<endl;}
};
struct CLASSC{
    CLASSC(int x,double y){
    cout<<"class C"<<endl;}
};
template<class T>T* Singleton<T>::m_pInstance = nullptr;
int main()
{
    Singleton<CLASSA>::Instance();Singleton<CLASSB>::Instance(1);Singleton<CLASSC>::Instance(1,3.14);cin.get();return 0;
}

29.shared_ptr与weak_ptr

shared_ptr 不能用c++原生的赋值初始化构建

#include <memory>
shared_ptr<int> p(new int); //正确
shared_ptr<int> p = new int; //编译器报错

当遇到shared_ptr循环引用的清况,把其中一个shared_ptr换成weak_ptr就能正常析构,因为weak_ptr不操作资源,不会增加引用计数。

30.拷贝构造和移动构造

编译器默认拷贝构造是浅拷贝,若类内有指针,则只拷贝指针的值,比如用B拷贝构造A,若B析构了,delete掉自己的指针,则A当中的指针失效,这种情况一定要自定义拷贝构造函数

某些情况下,用体积较大的复杂自定义类型的临时变量进行拷贝构造,则开销太大,可以使用右值移动构造函数,&&

31.字节对齐

struct test{
    
char a;
int b;
};
cout << offsetof(test,a) << endl; // 0
cout << offsetof(test,b) << endl; // 4

alignof alignas

struct test{
    
double a;
double b;
double c;
double d;
};
cout << alignof(test) <<  endl; //字节对齐方式为8字节
=============================
struct alignas(32) test{
    
double a;
double b;
double c;
double d;
};
cout << alignof(test) <<  endl; //字节对齐方式改为32字节,能提高内存访问效率

32.用c++11自带的chrono替代boost的timer