在C ++中破坏动态分配的内存(数组对象)

时间:2018-09-25 20:02:38

标签: c++ destructor dynamic-memory-allocation delete-operator

在下面,您将找到一个代码(编译/运行),该代码简要地调用了一个函数,该函数在堆上动态分配数组。

#include "stdafx.h"

#include <stdio.h>

class A
{

    public:

    A()
    {
        printf ( "constructor has been called !!! \n" );
    }

    ~A()
    {
        printf ( "destructor has been called !!! \n" );
    }

    char* f( void )
    {

        //char *data_raw = NULL;

        data_raw = NULL;

        data_raw = new char [ 20 ];

        for( int i = 0; i < 20; i++ )
        {
            data_raw[ i ] = '0';    
        }

        data_raw[  0 ] = 'h';
        data_raw[  1 ] = 'e';
        data_raw[  2 ] = 'l';
        data_raw[  3 ] = 'l';
        data_raw[  4 ] = 'o';
        data_raw[  5 ] = ' ';
        data_raw[  6 ] = 'w';
        data_raw[  7 ] = 'o';
        data_raw[  8 ] = 'r';
        data_raw[  9 ] = 'l';
        data_raw[ 10 ] = 'd';
        data_raw[ 11 ] = '!';

        return data_raw;

    } //data raw ptr-var is destroyed

    private:

        char *data_raw;

};


int  _tmain( int argc, _TCHAR* argv[] )
{

    char *data = NULL;

    printf( "data: %c", data );

    A a;

    data = a.f();

    delete [] data;  

    return 0;

}

我的问题:

1)关于破坏动态分配的内存,我应该使用delete还是delete []?他们都编译...

2)当我使用前一个(delete)时,将调用类析构函数,而不是当我使用delete []时?

2 个答案:

答案 0 :(得分:2)

您应该<永远>永远不要使用诸如A之类的类,尤其不要使用它的方式。

特别是:

  • 在保留指向所拥有对象的指针的同时,您不应转移内存的所有权(除非它是弱引用)。这几乎总是意味着您在错误地假设指针是有效的,尽管事实上,在使用非所有者指针之前很久很容易就可以重新分配内存。
  • 除非非常特殊的情况,否则您不应直接分配和取消分配内存。使用现有的容器类,或者如果不合适,请使用use smart pointers-std::unique_ptrstd::shared_ptrstd::weak_ptr-适当。
  • 您不应将指针传递给新所有者不知道已分配数量(或已分配数量的下限)的已分配内存。要么传递对适当对象的引用,要么使用move semantics传递容器,或者传递spans。请注意,当您只是简单地传递值(由于copy ellisions)时,可能会发生这种情况。
  • 通常,您应该更喜欢与创建者对象保持对内存的所有权,允许非所有权访问并让创建者对象销毁其创建的内容。

您的代码没有遵循这些准则!这很可怕,很危险!

我会按照您的准则重写您的代码,但是由于不清楚为什么您甚至需要方法f或A类,我最终只会遇到:

#include <iostream>
#include <string>

std::string A_f() { return "hello world"; }

int main( int argc, const char* argv[] )
{
    std::cout << A_f();
}

或者只是

#include <iostream>

int main( int argc, const char* argv[] )
{
    std::cout << "hello world";
}

答案 1 :(得分:1)

使用delete[]初始化堆中的数组时调用new,而使用delete初始化堆中的对象时使用new

在旁注中,我建议您删除类的所有者。如果您在这里做什么,将会给您带来很多麻烦。删除A之外的数组。

在此示例中,没有什么阻止您在类A的析构函数中调用delete[] data_raw。无需从A的外部对其进行修饰,甚至无需返回指向数组的指针。

class A
{
public:
   A()
  {
    printf ( "constructor has been called !!! \n" );
    data_raw = NULL;
    data_raw = new char [ 20 ];
    //....rest ofthe code from f( void )
    //....no need to return data_raw        
  }

  ~A()
  {
    printf ( "destructor has been called !!! \n" );
    delete [] data_raw; 
  }

private:
  char *data_raw;
};