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

destroying dynamically allocated memory (array object) in C++

您将在下面找到一段代码(compiles/runs),它简要地调用了一个在堆上动态分配数组的函数。

#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 ) 时, class 析构函数被调用,但当我使用 delete [] 时却没有?

你应该永远不要使用class,比如A,特别是不要以你的方式使用它。

具体来说:

  • 您不应在保留指向所拥有对象的指针的同时转移内存所有权(除非它是弱引用)。这几乎总是意味着您做出了指针有效的无效假设,尽管事实上在使用非拥有指针之前很久就可以很容易地释放内存。
  • 除非在非常特殊的情况下,否则不应直接分配和释放内存。使用现有容器 classes,或者如果 none 合适,则 use smart pointers - std::unique_ptrstd::shared_ptrstd::weak_ptr - 视情况而定。
  • 您不应该将指针传递给新所有者不知道分配量(或分配量的下限)的分配内存。传递对适当对象的引用,或使用 move semantics, or pass around. Note that this might happen when you simply just pass values around (due to copy ellisions).
  • 传递容器
  • 您通常应该更喜欢与创建者对象保持内存所有权,允许非拥有访问并让创建者对象销毁它创建的内容。

您的代码遵循 none 这些准则!这很可怕也很危险!

我会重写你的代码以遵循你的指导方针,但由于不清楚你为什么需要方法 f 或 class 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";
}

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

附带一提,我建议您删除 class 的所有者的成员。如果你在这里做你会自找麻烦。删除 A.

之外的数组

对于这个例子,没有什么可以阻止你在 class A 的析构函数中调用 delete[] data_raw。不需要从 A 的外部甚至 return 访问它指向数组的指针。

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;
};