交换指针后删除动态分配的内存
Delete dynamically allocated memory after swapping its pointer
我是C++的新手,想同时了解内存管理和指针。
假设我有下面的代码
int* p1;
int* p2;
int* p3 = new int[some size];
p1 = p3;
std::swap(p1,p2);
如何正确删除动态分配的内存? delete[] p3
够了吗?之后我也应该删除 p2
吗?
当你这样做时,口语中有些模糊:
delete x;
我们说“删除x
”。严格来说是错误的,因为删除的是x
.
指向的对象
通过 new
/new[]
分配的每个对象都必须通过一次调用 delete
/delete[]
来销毁。无论您有两个或更多指向同一个对象的指针都不会改变这一点。
int* p1 = nullptr;
int* p2 = nullptr;
int* p3 = new int[some size]; // p3 points to the array
p1 = p3; // p1 points to the same array
std::swap(p1,p2); // now p1 == nullptr, p2 points to the array
请注意,您的示例中的指针未初始化。读取它们的值会导致未定义的行为。因为这不是问题的关键,所以我通过初始化它们来避免这个问题。
通过 new []
创建了一个数组,您必须通过 delete []
删除该数组。你不能删除它两次。所以要么调用 delete[] p3;
要么调用 delete[] p2;
,但不能同时调用。
PS: 评论已经提到了智能指针,我也建议你阅读它们。现在你不应该使用原始拥有指针。拥有指针是您需要对其调用 delete
的指针,它“拥有”指向的对象。原始指针应该只用于“观察”,即您永远不需要担心在原始指针上调用 delete
(或 delete[]
)。当然你还需要注意指向的对象是否还活着,但这不是动态分配所特有的:
int* p;
{
int x = 42;
p = &x; // p points to x;
} // x goes out of scope
// here p is not a valid pointer anymore
要了解这里发生了什么,添加一些调试语句会有所帮助,即:
std::cout << p1 << " " << p2 << " " << p3 << "\n";
跟踪将产生如下输出:
0 0 0x15e7eb0
0x15e7eb0 0 0x15e7eb0
0 0x15e7eb0 0x15e7eb0
(注意我把p1和p1初始化为nullptr
)
p3 最初指向一些内存。在赋值 p1 = p3
之后,p1 现在指向与 p3 相同的内存地址。交换指针时,现在是 p2 指向与 p3 相同的内存地址。
这里有几点需要注意:
- 你 必须 将
delete[]
与相应的 new[]
配对(不要用 new[]
调用 delete
等等)
- 对已删除的对象调用 delete 是未定义的行为
- 对空指针调用 delete 是绝对安全的
如您所见,处理原始指针和内存分配很容易导致陷阱。通常建议使用智能指针,或者如果您有一个非拥有指针,则使用像 observer_ptr
这样的抽象来在代码中清楚地指示指针的用途。
我是C++的新手,想同时了解内存管理和指针。
假设我有下面的代码
int* p1;
int* p2;
int* p3 = new int[some size];
p1 = p3;
std::swap(p1,p2);
如何正确删除动态分配的内存? delete[] p3
够了吗?之后我也应该删除 p2
吗?
当你这样做时,口语中有些模糊:
delete x;
我们说“删除x
”。严格来说是错误的,因为删除的是x
.
通过 new
/new[]
分配的每个对象都必须通过一次调用 delete
/delete[]
来销毁。无论您有两个或更多指向同一个对象的指针都不会改变这一点。
int* p1 = nullptr;
int* p2 = nullptr;
int* p3 = new int[some size]; // p3 points to the array
p1 = p3; // p1 points to the same array
std::swap(p1,p2); // now p1 == nullptr, p2 points to the array
请注意,您的示例中的指针未初始化。读取它们的值会导致未定义的行为。因为这不是问题的关键,所以我通过初始化它们来避免这个问题。
通过 new []
创建了一个数组,您必须通过 delete []
删除该数组。你不能删除它两次。所以要么调用 delete[] p3;
要么调用 delete[] p2;
,但不能同时调用。
PS: 评论已经提到了智能指针,我也建议你阅读它们。现在你不应该使用原始拥有指针。拥有指针是您需要对其调用 delete
的指针,它“拥有”指向的对象。原始指针应该只用于“观察”,即您永远不需要担心在原始指针上调用 delete
(或 delete[]
)。当然你还需要注意指向的对象是否还活着,但这不是动态分配所特有的:
int* p;
{
int x = 42;
p = &x; // p points to x;
} // x goes out of scope
// here p is not a valid pointer anymore
要了解这里发生了什么,添加一些调试语句会有所帮助,即:
std::cout << p1 << " " << p2 << " " << p3 << "\n";
跟踪将产生如下输出:
0 0 0x15e7eb0
0x15e7eb0 0 0x15e7eb0
0 0x15e7eb0 0x15e7eb0
(注意我把p1和p1初始化为nullptr
)
p3 最初指向一些内存。在赋值 p1 = p3
之后,p1 现在指向与 p3 相同的内存地址。交换指针时,现在是 p2 指向与 p3 相同的内存地址。
这里有几点需要注意:
- 你 必须 将
delete[]
与相应的new[]
配对(不要用new[]
调用delete
等等) - 对已删除的对象调用 delete 是未定义的行为
- 对空指针调用 delete 是绝对安全的
如您所见,处理原始指针和内存分配很容易导致陷阱。通常建议使用智能指针,或者如果您有一个非拥有指针,则使用像 observer_ptr
这样的抽象来在代码中清楚地指示指针的用途。