在C++中,数组初始化有多种方式,以下是常见的几种方法:
数组元素未显式初始化时,内置类型(如int
、float
)的元素值未定义(垃圾值),类类型调用默认构造函数。
int arr1[5]; // 元素值未定义
使用花括号{}
直接初始化所有元素。若列表元素少于数组长度,剩余元素默认初始化(内置类型为0)。
int arr2[3] = {1, 2, 3}; // 完全初始化
int arr3[5] = {1, 2}; // 部分初始化,剩余为0
编译器自动推断数组长度,适用于初始化列表完整的情况。
int arr4[] = {1, 2, 3, 4}; // 编译器推断长度为4
使用空花括号{}
或={}
,所有元素初始化为0或默认值。
int arr5[3] = {}; // 全部初始化为0
int arr6[3]{}; // C++11统一初始化语法
字符数组可以用字符串字面量初始化,注意预留\0
的空间。
char str1[6] = "hello"; // 自动添加\0
char str2[] = "world"; // 编译器推断长度为6
支持省略等号、嵌套列表初始化等。
int arr7[2][3] { {1, 2, 3}, {4, 5, 6} }; // 多维数组初始化
每种方式适用于不同场景,需根据实际需求选择。列表初始化是推荐做法,因其清晰且能避免未定义行为。
常量指针指向的内容不可修改,但指针本身可以重新指向其他地址。
语法形式:const int* ptr
或 int const* ptr
。
示例:
const int value = 10;
const int* ptr = &value;
// *ptr = 20; // 错误:不能修改指向的内容
int another = 30;
ptr = &another; // 正确:指针本身可以修改
指针本身不可修改(必须初始化且不能指向其他地址),但可以通过指针修改指向的内容。
语法形式:int* const ptr
。
示例:
int value = 10;
int* const ptr = &value;
*ptr = 20; // 正确:可以修改指向的内容
// ptr = &another; // 错误:指针本身不能修改
从右向左读声明:
const int* ptr
→ “ptr is a pointer to a const int”(指向常量的指针)。int* const ptr
→ “ptr is a const pointer to int”(常量指针)。在C++中,字符串可以通过多种方式初始化,以下是常见的几种方法:
使用双引号直接初始化
std::string str = "Hello, World!";
使用构造函数初始化
std::string str1; // 默认构造函数,空字符串
std::string str2(5, 'a'); // 重复字符构造,结果为 "aaaaa"
std::string str3(str2); // 拷贝构造函数
使用字符数组初始化
char charArray[] = {'H', 'e', 'l', 'l', 'o'};
std::string str4(charArray, 5); // 从字符数组构造
使用部分字符串初始化
std::string original = "Hello, World!";
std::string str5(original, 7, 5); // 从原字符串的第7个字符开始取5个字符,结果为 "World"
使用迭代器初始化
std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'};
std::string str6(vec.begin(), vec.end());
访问字符
std::string str = "Hello";
char ch = str[0]; // 获取第一个字符 'H'
char ch_at = str.at(1); // 获取第二个字符 'e',会检查边界
修改字符串
str[0] = 'h'; // 修改第一个字符为 'h'
str.append(" World"); // 追加字符串,结果为 "hello World"
str.push_back('!'); // 追加单个字符,结果为 "hello World!"
str.insert(5, ", C++"); // 在位置5插入字符串,结果为 "hello, C++ World!"
str.erase(5, 5); // 从位置5删除5个字符,结果为 "hello World!"
str.replace(6, 5, "Universe"); // 从位置6替换5个字符,结果为 "hello Universe!"
字符串比较
在C++中,字符串的比较确实遵循字典序(lexicographical order)原则,即逐个字符进行对比。这种比较方式适用于标准库中的std::string
类以及C风格的字符串(如char*
)
std::string str1 = "apple";
std::string str2 = "banana";
bool isEqual = (str1 == str2); // false
bool isLess = (str1 < str2); // true
字符串长度和容量
size_t len = str.length(); // 或 str.size()
bool isEmpty = str.empty();
str.resize(10); // 调整字符串大小
size_t cap = str.capacity(); // 当前分配的存储空间
子串操作
std::string substr = str.substr(6, 8); // 从位置6开始取8个字符
size_t pos = str.find("Universe"); // 查找子串位置
输入输出操作
std::cout << str << std::endl;
std::cin >> str; // 输入字符串(遇到空格停止)
std::getline(std::cin, str); // 输入一行字符串
转换操作
const char* cstr = str.c_str(); // 转换为C风格字符串
int num = std::stoi("123"); // 字符串转整数
double d = std::stod("3.14"); // 字符串转浮点数
std::string numStr = std::to_string(123); // 数值转字符串
在C++中,结构体可以通过多种方式初始化。现代C++提供了灵活的初始化语法,包括聚合初始化、列表初始化以及构造函数初始化。
聚合初始化适用于没有用户定义构造函数、私有或保护非静态数据成员的结构体:
struct Point {
int x;
int y;
};
Point p1 = {10, 20}; // C风格聚合初始化
Point p2{30, 40}; // C++11列表初始化
对于包含构造函数的复杂结构体:
struct Employee {
std::string name;
int id;
Employee(std::string n, int i) : name(std::move(n)), id(i) {}
};
Employee e{"John", 1001};
结构体内存对齐遵循以下基本原则:
典型对齐值示例:
使用alignas指定对齐要求:
struct alignas(16) AlignedStruct {
char c;
int i;
double d;
};
通过#pragma pack修改默认对齐:
#pragma pack(push, 1)
struct PackedStruct {
char c;
int i;
};
#pragma pack(pop)
C++11标准布局类型要求:
计算结构体大小和对齐:
struct Example {
char a; // 偏移0
// 3字节填充
int b; // 偏移4
double c; // 偏移8
short d; // 偏移16
// 6字节填充(总大小需是8的倍数)
}; // 总大小24字节
跨平台注意事项:
vector
(动态数组)适用场景:
需要随机访问、尾部频繁插入/删除,元素连续存储的场景(如数据缓存、动态数据集)
#include
#include
int main() {
std::vector<int> nums{7, 3, 5}; // 初始化
nums.push_back(9); // 尾部插入
nums.pop_back(); // 尾部删除
std::cout << "元素: ";
for (int n : nums) std::cout << n << " "; // 遍历输出: 7 3 5
return 0;
}
适用场景:
固定大小的数据存储
std::array 适用于已知编译时确定大小的场景,例如存储固定数量的配置参数、物理常数或预定义表。其大小在编译时确定,避免了动态内存分配的开销。
constexpr std::array<double, 3> gravity = {9.7803, 9.832, 9.80665}; // 不同纬度重力加速度
需要 STL 接口兼容性
当算法需要接受 STL 兼容容器(如需要.begin()/.end()迭代器)时,std::array 可以直接替代 C 风格数组,无需额外适配。
std::array<int, 5> arr = {1,2,3,4,5};
std::sort(arr.begin(), arr.end()); // 直接使用 STL 算法
性能敏感场景
std::array 数据存储在栈上,访问速度与 C 风格数组相当,适合实时系统或高频调用的代码段。其内存局部性优于动态容器(如 std::vector)。
// 矩阵乘法中的小块操作
std::array<std::array<float, 4>, 4> matrix_multiply(const std::array<std::array<float, 4>, 4>& a, const std::array<std::array<float, 4>, 4>& b);
作为函数参数或返回值
std::array 支持值语义,可以安全地作为函数参数或返回值传递,避免指针和手动内存管理。
std::array<char, 16> generate_id() {
std::array<char, 16> id;
// ...填充数据
return id; // 返回值优化(RVO)确保高效
}
元编程与 constexpr 上下文
std::array 完全支持 constexpr,可在编译时计算中使用,配合模板元编程时尤其有用。
template<std::size_t N>
constexpr std::array<int, N> create_factorial_table() {
std::array<int, N> res{};
res[0] = 1;
for (int i=1; i<N; ++i) res[i] = res[i-1] * i;
return res;
}
替代 C 风格数组
std::array 提供.at()边界检查、size()方法等安全特性,同时保持相同性能,是 C 风格数组的类型安全替代品。
std::array<int, 10> safe_arr;
// safe_arr[10] = 5; // 未定义行为
safe_arr.at(10) = 5; // 抛出 std::out_of_range 异常
list
(双向链表)适用场景:
频繁在任意位置插入/删除,不需要随机访问(如任务队列、撤销操作栈)
#include
#include
int main() {
std::list<std::string> words{"apple", "banana"};
auto it = words.begin();
it++; // 指向第二个元素
words.insert(it, "orange"); // 在中间插入
words.erase(words.begin()); // 删除头部
for (auto& w : words)
std::cout << w << " "; // 输出: orange banana
return 0;
}
map
(红黑树字典)适用场景:
需要按键排序的键值对存储(如字典、配置参数)
#include
#include
int main() {
std::map<int, std::string> students;
students[101] = "Alice"; // 插入键值对
students[102] = "Bob";
students.erase(101); // 按键删除
for (auto& [id, name] : students)
std::cout << id << ":" << name << " "; // 输出: 102:Bob
return 0;
}
unordered_map
(哈希字典)适用场景:
需要快速查找的键值对,不要求顺序(如缓存系统、词频统计)
#include
#include
int main() {
std::unordered_map<std::string, int> wordCount;
wordCount["hello"] = 1; // 插入
wordCount["world"]++;
std::cout << wordCount.at("world"); // 输出: 1
return 0;
}
deque
(双端队列)适用场景:
频繁在头尾插入/删除(如滑动窗口、排队系统)
#include
#include
int main() {
std::deque<int> dq = {2, 3};
dq.push_front(1); // 头部插入
dq.push_back(4); // 尾部插入
dq.pop_front(); // 头部删除
for (int n : dq)
std::cout << n << " "; // 输出: 2 3 4
return 0;
}
set
(红黑树集合)适用场景:
需要自动排序的唯一元素集合(如黑名单、词典)
#include
#include
int main() {
std::set<int> uniqueNums = {5, 3, 5, 2}; // 自动去重
uniqueNums.insert(1);
if (uniqueNums.find(3) != uniqueNums.end())
std::cout << "3存在"; // 输出: 3存在
return 0;
}
stack
(栈)适用场景:
后进先出(LIFO)操作(如函数调用栈、表达式求值)
#include
#include
int main() {
std::stack<int> s;
s.push(10); s.push(20); // 压栈
std::cout << s.top() << " "; // 输出栈顶: 20
s.pop(); // 弹栈
std::cout << s.top(); // 输出: 10
return 0;
}
queue
(队列)适用场景:
先进先出(FIFO)操作(如消息队列、BFS算法)
#include
#include
int main() {
std::queue<std::string> q;
q.push("first"); // 入队
q.push("second");
std::cout << q.front() << " "; // 输出队首: first
q.pop(); // 出队
std::cout << q.front(); // 输出: second
return 0;
}
操作需求 | 推荐容器 |
---|---|
快速随机访问 | vector , array |
头尾频繁插入/删除 | deque |
中间频繁插入/删除 | list |
按键快速查找(有序) | map , set |
按键快速查找(无序) | unordered_map |
LIFO操作 | stack |
FIFO操作 | queue |
左值是指能够明确标识内存位置的表达式,通常可以取地址。左值具有持久性,例如变量、函数返回的左值引用等。
int x = 10; // x是左值
int* ptr = &x; // 可以取地址
右值通常是临时对象或字面量,没有明确的内存位置,不能取地址。右值包括纯右值(如临时对象、字面量)和将亡值(即将被移动的对象)。
int y = 20; // 20是右值
int z = x + y; // (x + y)的结果是右值
左值引用(T&
)只能绑定到左值,右值引用(T&&
)只能绑定到右值。
int a = 5;
int& lref = a; // 左值引用
int&& rref = 10; // 右值引用
移动语义通过右值引用避免不必要的拷贝,提升性能。std::move
将左值强制转换为右值引用,触发移动构造函数或移动赋值运算符。
class MyClass {
public:
MyClass() = default;
MyClass(MyClass&& other) noexcept { // 移动构造函数
// 转移资源
}
MyClass& operator=(MyClass&& other) noexcept { // 移动赋值运算符
if (this != &other) {
// 释放当前资源并转移
}
return *this;
}
};
MyClass obj1;
MyClass obj2 = std::move(obj1); // 调用移动构造函数
std::forward
保持参数的值类别(左值或右值),用于模板函数中实现完美转发。
template<typename T>
void wrapper(T&& arg) {
func(std::forward<T>(arg)); // 保持arg的原始类别
}
noexcept
,避免异常问题。std::move
仅转换类型,不执行移动操作,实际移动由构造函数或赋值运算符完成。核心思想:资源生命周期与对象绑定。对象构造时获取资源,析构时自动释放资源。避免内存泄漏和资源未释放问题。
class FileHandler {
public:
FileHandler(const std::string& path) : file_(fopen(path.c_str(), "r")) {}
~FileHandler() { if(file_) fclose(file_); } // 析构时自动释放
private:
FILE* file_;
};
动态类型识别机制:
dynamic_cast
:安全向下转型Base* b = new Derived();
if (Derived* d = dynamic_cast<Derived*>(b)) { /* 成功转换 */ }
typeid
:获取类型信息std::cout << typeid(*b).name(); // 输出实际类型名
限制:需启用RTTI编译选项(-frtti
),且类至少含一个虚函数。
MyClass obj; // 调用默认构造
std::vector<MyClass> v(10); // 元素默认构造
explicit
关键字禁止隐式类型转换:
class Timer {
public:
explicit Timer(int ms) {} // 阻止隐式转换
};
// Timer t = 1000; // 错误!必须显式:Timer t(1000);
适用场景:单参数构造函数,避免意外类型转换。
成员 | 签名格式 | 作用 |
---|---|---|
复制构造函数 | ClassName(const ClassName&) |
深拷贝对象 |
复制赋值运算符 | ClassName& operator=(const ClassName&) |
对象赋值时深拷贝 |
成员 | 签名格式 | 作用 |
---|---|---|
移动构造函数 | ClassName(ClassName&&) |
转移资源所有权 |
移动赋值运算符 | ClassName& operator=(ClassName&&) |
赋值时转移资源 |
class Buffer {
public:
Buffer(Buffer&& other) : data_(other.data_), size_(other.size_) {
other.data_ = nullptr; // 转移后置空原指针
}
private:
int* data_;
size_t size_;
};
特性 | 核心目的 | 典型应用场景 |
---|---|---|
RAII | 自动化资源管理 | 文件/锁/内存管理 |
RTTI | 运行时类型安全操作 | 多态类型检查 |
explicit |
防止意外隐式转换 | 单参数构造的包装类 |
移动语义 | 优化临时对象资源转移 | 容器操作/大对象传递 |
最佳实践:
- 优先使用
=default
/=delete
显式控制特殊成员函数- 移动构造函数应标记
noexcept
- 资源管理类必须禁用复制语义或实现深拷贝### C++面向对象重点知识总结
C++提供四种类型转换运算符:static_cast
、dynamic_cast
、const_cast
、reinterpret_cast
,用于替代C风格的强制转换,增强安全性和可读性。
用于编译时已知的静态类型转换,适用于相关类型间的转换(如基本类型、父子类指针等)。
double d = 3.14;
int i = static_cast<int>(d); // 基本类型转换
class Base {};
class Derived : public Base {};
Base* b = new Derived();
Derived* dd = static_cast<Derived*>(b); // 父子类指针转换(无运行时检查)
特点:
const
或volatile
属性。主要用于多态类型(含虚函数)的安全转换,依赖RTTI(运行时类型信息)。
class Base { virtual void foo() {} };
class Derived : public Base {};
Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b); // 成功
Base* bb = dynamic_cast<Base*>(d); // 上行转换总是安全
Base* invalid = new Base();
Derived* fail = dynamic_cast<Derived*>(invalid); // 返回nullptr(指针)或抛出异常(引用)
特点:
nullptr
(指针)或抛出std::bad_cast
(引用)。用于修改类型的const
或volatile
属性。
const int x = 10;
int* y = const_cast<int*>(&x); // 移除const
*y = 20; // 未定义行为(原变量可能为常量存储区)
void print(char* str) { cout << str; }
const char* msg = "hello";
print(const_cast<char*>(msg)); // 安全用法:函数参数非修改场景
特点:
int
→double
)。const
的值可能导致未定义行为。低级别重新解释位模式,用于无关类型间的危险转换。
int* p = new int(65);
char* ch = reinterpret_cast<char*>(p); // int* → char*
cout << *ch; // 输出'A'(ASCII 65)
uintptr_t addr = reinterpret_cast<uintptr_t>(p); // 指针转整数
特点:
C++中仍支持但 discouraged,行为相当于组合使用上述四种转换。
int a = (int)3.14; // 类似static_cast
Base* b = (Base*)new Derived(); // 可能类似static_cast或reinterpret_cast
const int* pc = &a;
int* pv = (int*)pc; // 类似const_cast
风险:
dynamic_cast
仅用于多态类型,避免性能开销。const_cast
慎用,确保逻辑正确性。reinterpret_cast
仅在底层编程(如硬件操作)中使用。template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
max(3, 5); // 推导为 int
max<double>(3.1, 2); // 显式指定
template <typename T>
class Stack {
private:
T elements[100];
int top;
public:
void push(T const&);
T pop();
};
Stack<int> intStack; // 存储 int 类型
Stack<std::string> strStack; // 存储 string 类型
template <typename T, int size>
class Array {
T data[size];
};
Array<double, 10> arr; // 大小为 10 的 double 数组
template <>
class Stack<bool> { // 针对 bool 类型的特化
// 优化存储(如位向量)
};
template <typename T>
class Stack<T*> { // 针对指针类型的偏特化
// 特殊处理指针
};
template <typename... Args>
void log(Args... args) {
// 使用折叠表达式或递归展开参数包
}
log("Error:", 42, 3.14); // 接受多个参数
template <int N>
struct Factorial {
static const int value = N * Factorial<N-1>::value;
};
template <>
struct Factorial<0> {
static const int value = 1;
};
int x = Factorial<5>::value; // 编译期计算 120
concepts
明确类型要求。vector
, map
)std::sort
, std::find
)shared_ptr
)智能指针是管理动态内存的RAII(资源获取即初始化)对象,自动释放内存,防止内存泄漏。主要类型:
std::unique_ptr
std::move
转移所有权std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
std::unique_ptr<int> ptr2 = std::move(ptr1); // ptr1变为nullptr
std::shared_ptr
auto ptr3 = std::make_shared<int>(100);
auto ptr4 = ptr3; // 引用计数+1
std::weak_ptr
shared_ptr
访问资源std::weak_ptr<int> weak = ptr3;
if (auto temp = weak.lock()) { // 尝试获取shared_ptr
// 使用*temp
}
特性 | unique_ptr |
shared_ptr |
weak_ptr |
---|---|---|---|
所有权 | 独占 | 共享 | 无所有权 |
复制语义 | ❌ | ✅ | ✅(不增计数) |
自定义删除器 | ✅ | ✅ | ❌ |
循环引用风险 | 无 | 有 | 解决方案 |
内存开销 | 极小 | 控制块开销 | 控制块开销 |
make_xxx
auto p = std::make_unique<MyClass>(); // 避免显式new
class Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 用weak_ptr打破循环
};
unique_ptr
作为工厂返回值std::unique_ptr<Base> createObject(int type) {
if (type == 1) return std::make_unique<Derived1>();
else return std::make_unique<Derived2>();
}
weak_ptr
检查资源有效性if (!weak.expired()) { // 检查资源是否存在
auto res = weak.lock();
}
int* raw = new int(10);
std::shared_ptr<int> p1(raw);
std::shared_ptr<int> p2(raw); // 错误!双重释放
FILE* f = fopen("file.txt", "r");
std::unique_ptr<FILE, decltype(&fclose)> file(f, &fclose); // 需指定删除器
shared_ptr
循环引用struct A { std::shared_ptr<B> b; };
struct B { std::shared_ptr<A> a; }; // 内存泄漏!
智能指针显著提升内存安全性,但需理解所有权语义。建议结合Valgrind/AddressSanitizer工具检测内存问题。
线程创建:使用std::thread
类
#include
void task() { /* 任务逻辑 */ }
std::thread t(task); // 创建线程
t.join(); // 等待线程结束
线程分离:detach()
使线程在后台运行
std::thread t(task);
t.detach(); // 主线程不再管理此线程
std::mutex
:基础互斥锁std::recursive_mutex
:可重入锁std::timed_mutex
:支持超时锁定std::mutex mtx;
void safe_increment(int& counter) {
mtx.lock();
++counter; // 临界区
mtx.unlock();
}
lock_guard
:RAII风格自动锁管理std::mutex mtx;
void safe_func() {
std::lock_guard<std::mutex> lock(mtx); // 构造时加锁,析构时解锁
// 临界区操作
}
unique_lock
:更灵活的锁(支持延迟锁定、转移所有权)std::mutex mtx;
void flexible_func() {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
lock.lock(); // 手动加锁
// 操作...
lock.unlock(); // 可手动解锁
}
std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
void producer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
data_queue.push(42);
cv.notify_one(); // 通知消费者
}
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return !data_queue.empty(); }); // 等待非空条件
int data = data_queue.front();
data_queue.pop();
}
}
#include
std::atomic<int> counter(0);
void increment() {
counter.fetch_add(1, std::memory_order_relaxed);
}
memory_order_relaxed
:宽松顺序memory_order_seq_cst
:严格顺序(默认)std::async
:异步执行函数
std::future
:获取异步结果
#include
int compute() { return 42; }
std::future<int> fut = std::async(compute);
int result = fut.get(); // 阻塞获取结果
std::packaged_task
:封装可调用对象(如函数、Lambda),执行结果与std::future绑定
#include
#include
#include
int main() {
// 封装Lambda任务(计算平方)
std::packaged_task<int(int)> task([](int x) {
return x * x;
});
// 获取关联的future
std::future<int> result = task.get_future();
// 在独立线程执行任务
std::thread t(std::move(task), 5);
t.detach();
// 获取结果(阻塞直到完成)
std::cout << "Result: " << result.get() << std::endl; // 输出25
}
std::promise
:显式设置异步操作的结果值或异常
#include
#include
void compute(std::promise<int> prom) {
try {
int res = 42; // 复杂计算
prom.set_value(res); // 设置结果
} catch(...) {
prom.set_exception(std::current_exception()); // 传递异常
}
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(compute, std::move(prom));
// 等待结果
std::cout << "Result: " << fut.get() << std::endl; // 输出42
t.join();
}
thread_local
)thread_local int local_var = 0; // 每个线程独立副本
std::lock()
同时锁定多个互斥量std::lock(mtx1, mtx2); // 原子化锁定
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
std::atomic_flag
实现自旋锁struct alignas(64) CacheLineAligned {
int data; // 单独缓存行
};
#pragma once
class MyMemoPool {
public:
static void* operator new(size_t size);
static void operator delete(void* pHead);
static int m_iCount; // 分配计数统计,每new一次+1
static int m_iMallocCount; // 统计malloc次数,每malloc一次+1
private:
MyMemoPool* next;
static MyMemoPool* m_FreePos; // 总是指向一块可以分配出去的内存首地址
static int m_sTrunkCount; // 一次分配多少倍该类的内存
};
#include "MyMemoPool.h"
#include
#define MYMEMPOOL 1
void* MyMemoPool::operator new(size_t size) {
#ifndef MYMEMPOOL
MyMemoPool* pPoint = (MyMemoPool*)malloc(size);
return pPoint;
#endif
MyMemoPool* tmpLink;
if (m_FreePos == nullptr) {
// 为空,我们要申请内存,申请很大一块内存
size_t realsize = m_sTrunkCount * size;
m_FreePos = reinterpret_cast<MyMemoPool*>(new char[realsize]);
tmpLink = m_FreePos;
// 把分配的这一大块内存链接起来,供后续使用
for (; tmpLink != &m_FreePos[m_sTrunkCount - 1]; ++tmpLink) {
tmpLink->next = tmpLink + 1;
}
tmpLink->next = nullptr;
++m_iMallocCount;
}
tmpLink = m_FreePos;
m_FreePos = m_FreePos->next;
++m_iCount;
return tmpLink;
}
void MyMemoPool::operator delete(void* pHead) {
#ifndef MYMEMPOOL
free(pHead);
return;
#endif // MYMEMPOOL
(static_cast<MyMemoPool*>(pHead))->next = m_FreePos;
m_FreePos = static_cast<MyMemoPool*>(pHead);
}
int MyMemoPool::m_iCount = 0;
int MyMemoPool::m_iMallocCount = 0;
MyMemoPool* MyMemoPool::m_FreePos = nullptr;
int MyMemoPool::m_sTrunkCount = 350;