C ++和何时使用删除

我刚刚重新阅读了一些C ++代码(我现在在学校学习Java),并且对于何时必须使用delete有点困惑。

例如:声明两个对象时:

Fraction* f1;
Fraction* f2;

并像这样创建f1和f2:

f1 = new Fraction(user_input1, user_input2);
f2 = new Fraction(user_input3, user_input4);

下一次我想使用new操作符创建一个新对象时,是否必须先删除? 我很困惑,因为我习惯于让java中的垃圾回收器负责处理对象并删除它们。 我需要删除才能再次使用新的?

if (f1) delete f1;

if (f2) delete f2;

//initialize again...

经验法则是每个new必须有相应的delete

在C ++中手动使用newdelete不是常见的事情。 当你初始化的事情,而无需使用newdelete其保证是由即将来处理你} 。 假设每个人都在做他们的工作,并且遵循RAII的原则。

Fraction f1(...);

实例化一个名为f1的Fraction对象。 它的析构函数在到达范围的末尾时会被调用。

'现代'的做法是处理上述事情。 在极少数情况下,这种方法不行,你应该使用智能指针。


有两种主要的方法来创建C ++选项。 一个在堆栈中(即Fraction f1; ),并且当该堆栈帧被弹出时该内存被自动释放。 第二个是在堆上(即Fraction* f1 = new Fraction();键是new关键字。

基本的总结是这样的:你的new的和delete s必须匹配。 每当你有new东西,你必须delete它,当你完成它。 “当你完成它时”由你来决定。 但是,如果您重新使用变量(请参见下文),则需要先delete变量,否则无法将原始对象恢复为delete

Fraction* f1 = new Fraction(); // create memory on heap, will need to free
f1 = new Fraction(); // this is a memory leak because I didn't first free the
                     // original f1 object, which I can no longer access

而不是告诉你何时使用delete ,我会尽力解释为什么你使用指针。 因此,您可以决定何时使用动态对象,如何使用它们以及何时调用delete (而不是)。


规则的拇指:

  • 尽可能使用静态对象,然后在需要时创建指向该实例的指针。 不需要delete电话。
  • 如果您创建一个指向动态对象的指针,请创建清理代码。 所以,当你写new也可以在合适的位置写下delete文件(并确保被调用)。
  • 对于每个new关键字,都需要有一个delete关键字。 否则,您正在使用机器的所有资源,导致应用程序崩溃或停止。 它也会使系统变慢。

  • 静态创建一个对象:

    Fraction f1;
    
  • 无需删除任何内容,即退出创建它时所处理的内容。
  • 动态创建对象:

    Fraction* f1;
    

    现在你有这个地址到堆上的内存块。 这是无效的,因为你没有分配任何东西。 好的做法是 - 根据你声明的位置 - 分配一个NULL(窗口)或0(跨平台)。

    Fraction* f1 = 0;
    

    何时使用delete

    只要你创建一个动态对象,从而调用new操作符,就需要在某处调用delete

    int main()
    {
    
        Fraction* f1 = 0;    // Good practise to avoid invalid pointers
                             // An invalid pointer - if( f1 ){ Access violation }
    
        f1 = new Fraction(); // Could have done this at the previous line
    
        /* do whatever you need */
    
        if( f1 )
        {
    
            delete f1; 
            f1 = 0;          // not needed since we are leaving the application
    
        }
    
        return 0;
    
    }
    

    在某些情况下,有一个Fraction数组或指针指向它可能是有用的。 这里使用int来简化,与跳过错误处理相同:

    int arr[ 10 ];
    int cur = -1;
    int* Add( int fraction )
    {
        arr[++cur] = fraction;
        return &arr[cur];
    }
    
    // Usage:
    Add( 1 );
    Add( 4 );
    

    有一件事发生在这里,没有通过动态对象分配给任何内存。 它们被自动释放。 函数返回的指针是指向静态内存块的指针。

    当把arr指向int的指针时:

    int* arr[ 10 ];
    int cur = -1;
    int* Add( int* fraction )
    {
        arr[++cur] = fraction;
        return arr[cur];
    }
    
    // Usage:
    int* test;
    
    test = Add( new int( 1 ) );
    test = Add( new int( 4 ) );
    

    现在你必须记忆块因为没有清理代码而泄漏。

    在每次Add(...) delete test后调用时,您已经清理了内存,但是您已经将int* arr[ 10 ]存储的值丢失,因为它们指向保存该值的内存。

    您可以创建另一个函数并在完成这些值后调用它:

    void CleanUp()
    {
        for( int a = 0; a < 10; ++a )
            delete arr[ a ];
    }
    

    小用法示例:

    int* test;
    int  test2;
    
    test  = Add( new int( 1 ) );
    test2 = *Add( new int( 4 ) ); // dereference the returned value
    
    /* do whatever you need */
    
    CleanUp();
    

    我们为什么要使用指针:

    int Add( int val )
    {
        return val; // indeed very lame
    }
    

    当你调用一个需要参数(类型)的函数时,你并没有传入实例,而是传入它的一个副本。 在上述功能中,您将返回该副本的副本。 它会占用大量的所有内存,导致应用程序的速度大大降低。

    考虑这个:

    class Test
    {
        int  t;
        char str[ 256 ];
    }
    

    如果一个函数需要一个类型Test,那么你需要复制int和256个字符。 因此,使该函数只需要一个指向Test的指针。 然后使用指针指向的内存并且不需要复制。

    int Add( int val )
    {
        val++;
        return val;
    }
    

    在最后一个例子中,我们将val的副本加1,然后返回该副本。

    int i = Add( 1 );
    

    结果: i = 2;

    void Add( int* val )
    {
        // mind the return type
        *val++;
    }
    

    在这个例子中,您将地址传递给一个值,然后 - 在取消引用之后 - 将值加1。

    int i = 1;
    Add( &i );
    

    结果: i = 2;

    现在你已经把地址传给了i ,而不是复制它。 在该函数中,您直接将1添加到该内存块的值。 因为你已经改变了记忆本身,所以你什么也没有返


    归零/测试有效指针

    有时您会遇到以下示例:

    if( p != 0 ) // or if( p )
    {
        /* do something with p */
    }
    

    这只是为了检查指针p是否有效。 但是,无效地址 - 因此不指​​向您保留的内存(访问冲突) - 也会通过。 对于您的代码,无效指针是有效的地址。

    因此,要使用这样的检查,你必须使用NULL(或0)指针。

    Fraction* f1 = 0;
    

    当f1 == 0时,它不指向任何东西,否则它指向它指向的任何东西。

    当你在一个'main'类中有一个指针或者没有被创建时,这是有用的。

    class Fraction
    {
        public:
        int* basicFeature;
        int* ExtendedFeature = 0; // NULL this pointer since we don't know if it
                                  // will be used
        Fraction( int fraction )
        {
            // Create a pointer owned by this class
            basicFeature = new int( fraction );
        }
        Fraction( int fraction, int extended ) // mind the static
        : Fraction( fraction )
        {
            // Create a pointer owned by this class
            ExtendedFeature = new int( extended );
        }
        ~Fraction()
        {
            delete basicFeature;
            if( ExtendedFeature )
                // It is assigned, so delete it
                delete ExtendedFeature;
        }
    }
    

    由于我们正在创造两个指针,因此我们正在清理那些指针。 只有检查ExtendedFeature,因为这个可能会或可能不会被创建。 basicFeature总是被创建。

    你可以通过调用一个新函数来替换if语句,包括它在dtor中的作用域: removeExtendedFeature()函数实现的位置:

    Fraction::removeExtendedFeature()
    {
        if( ExtendedFeature )
        {
            // It is assigned, so delete it
            delete ExtendedFeature;
            // Now it is important to NULL the pointer again since you would
            // get an access violation on the clean up of the instance of 
            // the class Fraction
            ExtendedFeature = 0;
        }
    }
    

    而新的dtor:

    Fraction::~Fraction()
    {
        delete basicFeature;
        removeExtendedFeature();
    }
    

    置零的另一个功能可能是:

    int Fraction::getValue()
    {
        int result = *basicFeature;
        if( ExtendedFeature )
            result += *ExtendedFeature;
        return result;
    }
    

    我为跛级班级道歉,还有一个更加蹩脚的扩展功能。 但作为一个例子,它可以达到目的。

    链接地址: http://www.djcxy.com/p/96539.html

    上一篇: C++ and when to use delete

    下一篇: What is safe? returning a structure or the pointer from a function