b站Cherno的课[81]-[85]
- 一、C++的可视化基准测试
- 二、C++的单例模式
- [三、C++的小字符串优化 sso](#三、C++的小字符串优化 sso)
- 四、跟踪内存分配的简单方法
- 五、C++的左值与右值
一、C++的可视化基准测试
chrome://tracing/
总结: cpp的计时器配合自制简易json配置写出类,将时间分析结果写入一个json文件,用chrome://tracing 这个工具进行可视化
cherno演示代码地址:https://gist.github.com/TheCherno/31f135eea6ee729ab5f26a6908eb3a5e
b站大神项目地址:https://github.com/GavinSun0921/InstrumentorTimer
二、C++的单例模式
单例是一个类的单一实例
单例就是外表为类形式的命名空间
当我们想要拥有应用于某种全局数据集的功能,
且我们只是想要重复使用时,单例是非常有用的
应用:
随机数生成器类
渲染器
cpp
#include <iostream>
class Singleton
{
public:
Singleton(const Singleton&) = delete;
static Singleton& Get()
{
return s_Instance;
}
void Function() {}
private:
Singleton() {}
float m_Member = 0.0f;
static Singleton s_Instance;
};
Singleton Singleton::s_Instance;
int main()
{
//Singleton& instance = Singleton::Get();
auto& instance = Singleton::Get();
Singleton::Get().Function();
}
cpp
#include <iostream>
// 随机数生成器类
class Random
{
public:
Random(const Random&) = delete;
// 单例的核心就是Get函数
static Random& Get()
{
return s_Instance;
}
static float Float() { return Get().IFloat(); }
private:
//internal内部的Float函数
float IFloat() { return m_RandomGenerator; }
Random() {}
float m_RandomGenerator = 0.5f;
static Random s_Instance;
};
Random Random::s_Instance;
int main()
{
auto& random = Random::Get();
float number = random.Float();
std::cout << number << std::endl;
std::cin.get();
}

一旦我有了这个单例,我可以简单地写任何数量的非静态方法并通过Get函数访问它们
或者如果我想的话,我可以删掉一层交互
(指不通过Get().来调用成员函数,而是直接写static函数来包装)
然后编写这些静态函数,在内部映射到可以访问成员数据和类的所有功能的成员函数
三、C++的小字符串优化 sso
我们不喜欢字符串的原因之一:
是它们倾向于分配内存,C++(快)\ 堆分配(慢),不好
因为我们知道创建一个标准的字符串会导致内存分配 ,
所以很多人会尽量避免,他们会尽量减少字符串的使用
换句话说,如果你有一个非常小的字符串,你就不需使用const char*
或者试图微观管理或优化你的代码
因为这可能不会导致堆分配
cpp
#include <iostream>
#include <string>
void* operator new(size_t size)
{
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
}
int main()
{
std::string name = "wm";
std::cin.get();
}
小字符串优化 sso:
足够小的字符串不会导致任何堆分配,因此会使您的程序运行得更快
四、跟踪内存分配的简单方法
cpp
#include <iostream>
#include <memory>
void* operator new(size_t size)
{
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
}
void operator delete(void* memory)
{
free(memory);
}
struct Object
{
int x, y, z;
};
int main()
{
{
std::unique_ptr<Object> obj = std::make_unique<Object>();
}
std::string name = "wm";
std::cin.get();
}

cpp
#include <iostream>
#include <memory>
void* operator new(size_t size)
{
std::cout << "Allocating " << size << " bytes\n";
return malloc(size);
}
void operator delete(void* memory, size_t size)
{
std::cout << "Freeing " << size << " bytes\n";
free(memory);
}
struct Object
{
int x, y, z;
};
int main()
{
{
std::unique_ptr<Object> obj = std::make_unique<Object>();
}
std::string name = "wm";
std::cin.get();
}

cpp
#include <iostream>
#include <memory>
struct AllocationMetrics
{
uint32_t TotalAllocated = 0;
uint32_t TotalFreed = 0;
uint32_t CurrentUsage() { return TotalAllocated - TotalFreed; }
};
static AllocationMetrics s_AllocationMetrics;
void* operator new(size_t size)
{
s_AllocationMetrics.TotalAllocated += size;
return malloc(size);
}
void operator delete(void* memory, size_t size)
{
s_AllocationMetrics.TotalFreed += size;
free(memory);
}
struct Object
{
int x, y, z;
};
static void PrintMemoryUsage()
{
std::cout << "Memory Usage: " << s_AllocationMetrics.CurrentUsage() << "bytes\n";
}
int main()
{
PrintMemoryUsage();
std::string name = "wm";
PrintMemoryUsage();
{
std::unique_ptr<Object> obj = std::make_unique<Object>();
PrintMemoryUsage();
}
PrintMemoryUsage();
std::cin.get();
}
Valgrind 也有一些很好的工具来跟踪内存,看看它来自哪里,如何分配等等
注:Valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具
五、C++的左值与右值
移动move语义
cpp
#include <iostream>
void PrintName(const std::string& name)
{
std::cout << "[lvalue] " << name << std::endl;
}
void PrintName(std::string&& name)
{
std::cout << "[rvalue] " << name << std::endl;
}
int main()
{
std::string firstName = "Yan";
std::string lastName = "Chernikov";
std::string fullName = firstName + lastName;
PrintName(fullName);
PrintName(firstName + lastName);
std::cin.get();
}
左值是有某种存储支持的变量,右值是临时值
左值引用仅仅接受左值,除非用const
右值引用仅仅接受右值
如果你在处理一个右值引用,,如果你能从那个临时值中偷取资源,因为它是临时的,这对优化有很大帮助
总结:
左值有地址和值,可以出现在赋值运算符左边或者右边。
右值只有值,只能出现在赋值运算符右边。&&
右值只有值,没有地址, 右值是一个优化技巧(C++),因为右值往往是临时变量的。