如果我在 C++ 中删除一次数组,但多次分配它怎么办?
What if I delete an array once in C++, but allocate it multiple times?
假设我有以下片段。
int main()
{
int num;
int* cost;
while(cin >> num)
{
int sum = 0;
if (num == 0)
break;
// Dynamically allocate the array and set to all zeros
cost = new int [num];
memset(cost, 0, num);
for (int i = 0; i < num; i++)
{
cin >> cost[i];
sum += cost[i];
}
cout << sum/num;
}
` `delete[] cost;
return 0;
}
尽管我可以在 while 循环中移动 delete
语句
对于我的代码,出于理解的目的,我想知道代码在编写时会发生什么。每次使用运算符new
时,C++是否分配不同的内存空间?
operator delete
是否仅删除分配给 cost
数组的 last?
每次为数组分配新内存时,之前分配的内存都会泄漏。根据经验,您需要释放内存的次数与分配的次数一样多。
是的。因此,除了最后一次之外,循环的每次迭代都会发生内存泄漏。
当您使用 new
时,您分配了一块新的内存。将 new
的结果分配给一个指针只会改变这个指针指向的内容。它不会自动释放此指针之前引用的内存(如果有的话)。
Does C++ allocate different memory spaces each time I use operator new
?
是的。
Does operator delete
only delete the last allocated cost
array?
是的。
您丢失了指向其他人的唯一指针,因此它们不可逆转地泄露了。为了避免这个问题,不要玩弄指针,而是使用 RAII 来自动管理动态资源。 std::vector
在这里是完美的(如果你真的需要一个数组;你的例子可以继续阅读并重新使用一个 int
)。
第一行错的是:
memset(cost, 0, num);
它假设一个整数只有一个字符长。更典型的是四个。如果你想使用 memset 来初始化数组,你应该使用这样的东西:
memset(cost, 0, num*sizeof(*cost));
或者更好的是转储 memset 并在分配内存时使用它:
cost = new int[num]();
正如其他人所指出的,delete 放置不正确,将泄漏由其相应的 new 分配的所有内存,除了最后一个。将其移动到循环中。
您的代码中没有 cost
数组。在您的代码中 cost
是一个 指针 ,而不是一个数组。
您代码中的实际 数组 是通过重复 new int [num]
调用创建的。每次调用 new 都会创建一个新的、独立的 nameless 数组对象,该对象位于动态内存中的某个位置。新数组一旦由 new[]
创建,就可以通过 cost
指针访问。由于数组是 nameless,因此 cost
指针是 only link 导致创建的无名数组通过 new[]
。您没有其他方法可以访问该无名数组。
每次你在你的循环中这样做 cost = new int [num]
,你就在创建一个全新的、不同的数组,将 link 从 cost
打破到前一个数组并使 cost
指向新的。
由于 cost
是您对旧数组的唯一 link,旧数组将无法访问。对那个旧数组的访问将永远丢失。它变成了内存泄漏。
正如您自己正确陈述的那样,您的 delete[]
表达式仅取消分配最后一个数组 - cost
最后指向的数组。当然,只有当您的代码执行了 cost = new int [num]
行时,这才是正确的。请注意,您的循环可能会在不进行单个分配的情况下终止,在这种情况下,您将 delete[]
应用于未初始化(垃圾)指针。
我强烈建议您不要在C++程序中使用"C idioms"。让 std
图书馆 为 你工作:这就是它存在的原因。如果你想要 "an array (vector) of n integers," 那么这就是 std::vector
的全部内容, 和 它 "comes with batteries included." 你 不要不必对 "setting a maximum size" 或 "setting it to zero." 之类的事情胡闹 你只需与 "this thing," 一起工作,你不必 [必须...] 关心其内部运作, 知道它已经经过彻底的设计和测试。
此外,当您这样做时,您是在 C++ 现有的内存管理框架内工作。特别是,您没有在自己的应用程序中执行任何操作 "out-of-band" "that the standard library doesn't know about, and which might (!!) it up."
C++ 为您提供了一个非常全面的库,其中包含快速、高效、健壮、经过良好测试的功能。 利用它。
假设我有以下片段。
int main()
{
int num;
int* cost;
while(cin >> num)
{
int sum = 0;
if (num == 0)
break;
// Dynamically allocate the array and set to all zeros
cost = new int [num];
memset(cost, 0, num);
for (int i = 0; i < num; i++)
{
cin >> cost[i];
sum += cost[i];
}
cout << sum/num;
}
` `delete[] cost;
return 0;
}
尽管我可以在 while 循环中移动 delete
语句
对于我的代码,出于理解的目的,我想知道代码在编写时会发生什么。每次使用运算符new
时,C++是否分配不同的内存空间?
operator delete
是否仅删除分配给 cost
数组的 last?
每次为数组分配新内存时,之前分配的内存都会泄漏。根据经验,您需要释放内存的次数与分配的次数一样多。
是的。因此,除了最后一次之外,循环的每次迭代都会发生内存泄漏。
当您使用 new
时,您分配了一块新的内存。将 new
的结果分配给一个指针只会改变这个指针指向的内容。它不会自动释放此指针之前引用的内存(如果有的话)。
Does C++ allocate different memory spaces each time I use operator
new
?
是的。
Does operator
delete
only delete the last allocatedcost
array?
是的。
您丢失了指向其他人的唯一指针,因此它们不可逆转地泄露了。为了避免这个问题,不要玩弄指针,而是使用 RAII 来自动管理动态资源。 std::vector
在这里是完美的(如果你真的需要一个数组;你的例子可以继续阅读并重新使用一个 int
)。
第一行错的是:
memset(cost, 0, num);
它假设一个整数只有一个字符长。更典型的是四个。如果你想使用 memset 来初始化数组,你应该使用这样的东西:
memset(cost, 0, num*sizeof(*cost));
或者更好的是转储 memset 并在分配内存时使用它:
cost = new int[num]();
正如其他人所指出的,delete 放置不正确,将泄漏由其相应的 new 分配的所有内存,除了最后一个。将其移动到循环中。
您的代码中没有 cost
数组。在您的代码中 cost
是一个 指针 ,而不是一个数组。
您代码中的实际 数组 是通过重复 new int [num]
调用创建的。每次调用 new 都会创建一个新的、独立的 nameless 数组对象,该对象位于动态内存中的某个位置。新数组一旦由 new[]
创建,就可以通过 cost
指针访问。由于数组是 nameless,因此 cost
指针是 only link 导致创建的无名数组通过 new[]
。您没有其他方法可以访问该无名数组。
每次你在你的循环中这样做 cost = new int [num]
,你就在创建一个全新的、不同的数组,将 link 从 cost
打破到前一个数组并使 cost
指向新的。
由于 cost
是您对旧数组的唯一 link,旧数组将无法访问。对那个旧数组的访问将永远丢失。它变成了内存泄漏。
正如您自己正确陈述的那样,您的 delete[]
表达式仅取消分配最后一个数组 - cost
最后指向的数组。当然,只有当您的代码执行了 cost = new int [num]
行时,这才是正确的。请注意,您的循环可能会在不进行单个分配的情况下终止,在这种情况下,您将 delete[]
应用于未初始化(垃圾)指针。
我强烈建议您不要在C++程序中使用"C idioms"。让 std
图书馆 为 你工作:这就是它存在的原因。如果你想要 "an array (vector) of n integers," 那么这就是 std::vector
的全部内容, 和 它 "comes with batteries included." 你 不要不必对 "setting a maximum size" 或 "setting it to zero." 之类的事情胡闹 你只需与 "this thing," 一起工作,你不必 [必须...] 关心其内部运作, 知道它已经经过彻底的设计和测试。
此外,当您这样做时,您是在 C++ 现有的内存管理框架内工作。特别是,您没有在自己的应用程序中执行任何操作 "out-of-band" "that the standard library doesn't know about, and which might (!!) it up."
C++ 为您提供了一个非常全面的库,其中包含快速、高效、健壮、经过良好测试的功能。 利用它。