将"delete"放入循环中的何处

Where to put "delete" in the loop

本文关键字:何处 循环 delete      更新时间:2023-10-16

假设我有以下代码:

int decreasingTest(int number){
int numberOfDigits = 0; do { number /= 10; numberOfDigits++; } while (number != 0);
int *arrayValue = new int[numberOfDigits + 1];
for(int i = numberOfDigits;0<=i;i--){ //acquire digits of number
    arrayValue[i] = (number - fmod(number, pow(10, i))) / pow(10, i);
    number = fmod(number, pow(10, i));
    i--;
}
for (int j = 0; j < sizeOfArray; j++){
    if (arrayValue[j + 1] <= arrayValue[j]){
        if ((j + 1) == sizeOfArray){
            cout << "The number's digits are decreasing." << endl;
            return 5;
        }
        continue;
    }
    return 0;
}

}

我应该把delete arrayValue[]放在return 0之前的行中,放在continue之后的括号之后,行return 0之后,还是放在最后一个括号之前的行中?

代码中有三个位置可以从函数返回:

  1. return 5线上
  2. return 0线上,循环后
  3. 在右大括号之前,如果外部循环从未执行。

为了不泄漏资源,每执行一次new调用,必须执行一次delete调用。在您的情况下,由于您有两个返回点,因此您需要两个delete调用 - 一个在每个返回点之前。

像您在此处所做的那样手动管理动态内存是有问题的。 很容易忘记删除某些内容,尤其是当您有多个返回点时。 已经构建了许多语言功能和库组件来解决此问题。 像shared_ptr和unique_ptr这样的智能指针会自动管理动态分配资源的销毁,因此您根本不需要编写delete,并且make_sharedmake_unique使您能够甚至永远不编写new。 (注意:make_unique不在 C++11 标准中,但它很容易编写,并且预计在 C++14 标准中。

由于多种原因,C 样式数组本身也存在问题。 最明显的是它们的固定大小和经常附带的神奇数字。 语言功能和库组件也存在来解决这个问题,我建议作为一项规则,你应该(几乎)永远不要使用 C 风格的数组。 请改用矢量。

在您的情况下,您根本不需要指针。 你只需要一个"向量":

std::vector <int> arrayValue;
for(int i = numberOfDigits;0<=i;i--){ //acquire digits of number
    arrayValue.push_front(number - fmod (number, pow(10, i))) / pow(10,i);
    //arrayValue[i] = (number - fmod(number, pow(10, i))) / pow(10, i);
    number = fmod(number, pow(10, i));
    i--;
}
...

对于这种特殊情况,没有理由使用动态内存。不是想变得迂腐,而是动态内存在很多不应该被使用的地方。

[增编(进一步资料和无耻地抢夺可能的观点)]

您可能会认为所需的位数已经在标准库中,因为十进制表示非常普遍。以下内容基于 Hallvard Furuseth 在 Google Group comp.std.c 中的帖子,但我不会从初始位大小计数中扣除符号位,因此它应该适用于有符号和无符号类型。+3 项表示存储因子"1"所需的数字 (log10(1)=0);符号"+"或"-";以及可能的空终止字符。146/485 的因子仅略大于 log10(2)(在任何基数中相当于 log(2)/log(10)),这是从二进制到十进制表示的数字比例因子。如果您发现任何问题,请告诉我。

//Overestimate for number of decimal digits representing an integer of type integerType
//Works for both signed and unsigned integer types
//Includes space for sign ('+' or '-') and for a termination character
//Upper-bounds the function floor(log10(abs(n))) + 3
#define SIZEDIGITS(integerType) (((sizeof(integerType)*CHAR_BIT)*146)/485 + 3)

int8_t:5 位数字 ("+/-127\0")

uint8_t:5 位数字 ('+255\0')

近似值给出 (8*146)/485 + 3 = 5 位数字

int16_t:7 位数字 ('+/-32767\0')

uint16_t:7 位数字 ('+65536\0')

近似给出 (16*146)/485 + 3 = 7 位数字

int32_t:12 位数字 ('+/-2147483647\0')

uint32_t:12 位数字 ("+4294967295\0")

近似值给出 (32*146)/485 + 3 = 12 位数字

int64_t:21 位数字 ("+/-9223372036854775807\0")

uint64_t:22 位数字 ("+18446744073709551615\0")

近似值给出 (64*146)/485 + 3 = 22 位数字

int128_t:41 位数字

uint128_t:41 位数字

近似给出 (128*146)/485 + 3 = 41 位数字

int9999_t(假装):3012 位数字

uint9999_t(假装):3012 位数字

近似给出 (9999*146)/485 + 3 = 3013(一个未使用的字节 - 人类!

(您可能知道也可能不知道的随机奖励事实:base-e 被认为是最有效的实数基数,就我们通常的实数幂和数字表示而言。三元在这方面优于二进制,因为它更接近e。

鉴于您现在拥有的代码结构,您需要将 delete [] arrayValue; 命令放在三个不同的位置(注意,[]arrayValue 之前,而不是在它之后)。您需要将其放在return 5;正上方的行上,return 0;正上方的行上,以及最后一个括号的正前方。代码可能会在这三行中的任何一行上退出函数,在这种情况下,您应该在退出函数之前立即释放内存。

或者,您可以将行int *arrayValue = new int[numberOfDigits + 1];替换为 std::vector<int> arrayValue(numberOfDigits + 1) ,并让编译器为您处理分配/解除分配。

您也可以

使用智能指针,例如 std::unique_ptr (http://en.cppreference.com/w/cpp/memory/unique_ptr),当指针超出范围时,它会自动释放动态分配的数组。

  1. 最重要的一点是,几乎从来没有一种情况是你应该再new数组了。我强烈建议你在这里使用std::vector,这样你的int *arrayValue = new int[numberOfDigits + 1];就会变成: std::vector<int> arrayValue(numberOfDigits + 1);而且你不需要做其他代码更改。

    请注意,在代码可能出错的情况下,例如,假设您的一个pow抛出并且您离开此函数而不返回,std::vector仍然会自行清理,这是new ed 内存无法说的。

  2. 如果您发现自己处于应该管理自己的记忆的 1% 情况中。一个好的经验法则是永远不要有多个返回语句。它只会使您的代码不可读且不可维护。因此,您应该将最后一个循环更改为:


    int result = 0;
    int j = 0;


    while(j < sizeOfArray - 1 && arrayValue[j + 1] <= arrayValue[j]){
    j++;
    }


    if (j == sizeOfArray - 1){
    cout << "The number's digits are decreasing." << endl;
    result = 5;
    }
    delete[] arrayValue;
    return result;

当您

应该使用在标头 <memory> 中声明的标准智能指针std::unique_ptr时。例如

std::unique_ptr<int[]> arrayValue( new int[numberOfDigits + 1] );

在这种情况下,您无需为删除数组而烦恼。