new关键字是C++中用于在堆上动态分配内存的操作符。它不仅分配内存,还会调用对象的构造函数进行初始化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
using String = std::string;
class Entity
{
private:
String m_Name;
public:
Entity() : m_Name("Unknown") {}
Entity(const String& name) : m_Name(name) {}
const String& GetName() const { return m_Name; }
};
int main()
{
// 分配单个对象
Entity* e = new Entity();
std::cout << e->GetName() << std::endl;
delete e; // 必须手动释放
// 带参数的构造
Entity* e2 = new Entity("Player");
std::cout << e2->GetName() << std::endl;
delete e2;
}
|
1
2
3
4
5
6
7
8
9
10
11
|
int main()
{
// malloc只分配内存,不调用构造函数
Entity* e1 = (Entity*)malloc(sizeof(Entity));
// e1指向的内存未初始化,成员变量处于未定义状态
// 需要手动调用构造函数(复杂且不安全)
// new (e1) Entity(); // placement new
free(e1); // 使用free释放,不会调用析构函数
}
|
1
2
3
4
5
6
7
8
|
int main()
{
// new既分配内存又调用构造函数
Entity* e = new Entity();
// e指向的对象已经完全初始化
delete e; // delete会调用析构函数然后释放内存
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
int main()
{
// 分配基本类型数组
int* numbers = new int[50]; // 分配50个int,200字节
// 初始化数组
for (int i = 0; i < 50; ++i)
{
numbers[i] = i;
}
delete[] numbers; // 注意:数组要用delete[]
// 分配对象数组
Entity* entities = new Entity[10]; // 调用10次默认构造函数
for (int i = 0; i < 10; ++i)
{
std::cout << entities[i].GetName() << std::endl;
}
delete[] entities; // 调用10次析构函数
}
|
placement new允许在指定的内存位置构造对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
int main()
{
// 先分配一块内存
char* buffer = new char[sizeof(Entity)];
// 在指定位置构造对象
Entity* e = new(buffer) Entity("Placed");
std::cout << e->GetName() << std::endl;
// 手动调用析构函数
e->~Entity();
// 释放原始内存
delete[] buffer;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <memory>
int main()
{
// 分配一块可以容纳多个Entity的内存
void* memory = new char[sizeof(Entity) * 3];
// 在内存中的不同位置构造对象
Entity* e1 = new(memory) Entity("First");
Entity* e2 = new((char*)memory + sizeof(Entity)) Entity("Second");
Entity* e3 = new((char*)memory + sizeof(Entity) * 2) Entity("Third");
std::cout << e1->GetName() << std::endl;
std::cout << e2->GetName() << std::endl;
std::cout << e3->GetName() << std::endl;
// 手动调用析构函数
e1->~Entity();
e2->~Entity();
e3->~Entity();
// 释放内存
delete[] (char*)memory;
}
|
可以重载new操作符来自定义内存分配行为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
class CustomEntity
{
private:
String m_Name;
public:
CustomEntity(const String& name) : m_Name(name) {}
// 重载new操作符
void* operator new(size_t size)
{
std::cout << "Custom new called, size: " << size << std::endl;
return malloc(size);
}
// 重载delete操作符
void operator delete(void* ptr)
{
std::cout << "Custom delete called" << std::endl;
free(ptr);
}
const String& GetName() const { return m_Name; }
};
int main()
{
CustomEntity* e = new CustomEntity("Custom"); // 调用自定义new
std::cout << e->GetName() << std::endl;
delete e; // 调用自定义delete
}
|
new可能抛出异常,需要注意异常安全:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#include <new>
int main()
{
try
{
// 如果内存不足,new会抛出std::bad_alloc异常
Entity* e = new Entity("Test");
// 使用对象...
delete e;
}
catch (const std::bad_alloc& ex)
{
std::cout << "Memory allocation failed: " << ex.what() << std::endl;
}
// 使用nothrow版本,失败时返回nullptr而不抛异常
Entity* e2 = new(std::nothrow) Entity("Safe");
if (e2)
{
std::cout << e2->GetName() << std::endl;
delete e2;
}
else
{
std::cout << "Memory allocation failed" << std::endl;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <memory>
int main()
{
// 使用make_unique(推荐)
auto e1 = std::make_unique<Entity>("Smart");
std::cout << e1->GetName() << std::endl;
// 自动释放,无需delete
// 使用make_shared
auto e2 = std::make_shared<Entity>("Shared");
std::cout << e2->GetName() << std::endl;
// 自动释放,无需delete
// 数组版本
auto numbers = std::make_unique<int[]>(50);
for (int i = 0; i < 50; ++i)
{
numbers[i] = i;
}
// 自动释放
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include <vector>
int main()
{
// 使用vector代替动态数组
std::vector<Entity> entities;
entities.emplace_back("Entity1");
entities.emplace_back("Entity2");
entities.emplace_back("Entity3");
for (const auto& entity : entities)
{
std::cout << entity.GetName() << std::endl;
}
// 自动管理内存
}
|
1
2
3
4
5
|
void BadFunction()
{
Entity* e = new Entity();
// 忘记delete e; 导致内存泄漏
}
|
1
2
3
4
5
6
|
void BadFunction()
{
Entity* e = new Entity();
delete e;
delete e; // 错误:重复删除
}
|
1
2
3
4
5
6
7
8
|
void BadFunction()
{
Entity* entities = new Entity[10];
delete entities; // 错误:应该用delete[]
Entity* e = new Entity();
delete[] e; // 错误:应该用delete
}
|
- new的主要目的是在堆上分配内存,new返回一个指针
- new会调用对象的构造函数,这是与malloc的主要区别
- new分配的内存必须用delete手动释放,数组用delete[]
- 现代C++建议:优先使用智能指针(make_unique、make_shared)而不是裸指针
- placement new:可以在指定内存位置构造对象,用于高级内存管理