如何在结构内部释放指针?

时间:2011-11-09 15:58:13

标签: c++ recursion structure destructor

我是结构新手所以请耐心等待。我写了一个名为gnt的结构,包含一个整数指针,一个整数和一个布尔值:

struct gnt
{
    unsigned int* num;
    unsigned int size;
    bool negative;
};

因为我将任意长度的int数组分配给各种gnt变量(即。k.num = new int*[j])(对于某些值j),我需要以某种方式释放它们。我不知道该怎么做。我只是使用delete[] k.num;(其中k是gnt)?我不得不担心结构本身吗?

另外,作为一个附带问题,我写了一个递归函数来乘以列表中的项目:

char* chain_multi(char** list, unsigned int start, unsigned int end)
{
    /***************************************************************
    This function recursively multiply every items in a list then
    return the product.
    ***************************************************************/
    unsigned int size = start - end + 1;
    if(size == 1)
        return copy_char(list[end]);
    if(size == 2)
        return multiplication(list[start], list[end]);

    int rs = start - size / 2;
    char* right = chain_multi(list, rs, end);
    char* left = chain_multi(list, start, rs + 1);
    char* product = multiplication(left, right);
    delete[] left;
    delete[] right;
    return product;
}

这会在没有递归的情况下提供任何优势吗?我测试了各种大小的列表(10到10000个条目之间)并且似乎没有任何时间优势...递归代码比其对应的短。

感谢您的任何意见。

4 个答案:

答案 0 :(得分:3)

遵守规则:
您应该将同一地址传递给您从delete[]收到的new[] 如果您只在freestore上分配了一个成员,那么您只需要解除分配。

您使用k.num分配了成员new [],所以是的,您应该仅为此致电delete []

此外,您可以使用std::vector而不是自己进行内存管理(除非这是一些限制您这样做的糟糕任务)


Standerdese粉丝:
标准C ++03§3.7.4.2-3:

  

如果通过抛出异常终止释放函数,则行为未定义。提供给解除分配函数的第一个参数的值可以是空指针值;如果是这样,并且如果解除分配功能是标准库中提供的功能,则该呼叫无效。否则,提供的值   标准库中的运算符delete(void*)应该是先前调用标准库中的运算符new(std::size_t)operator new(std::size_t, const std::nothrow_-t&)返回的值之一,并且值提供给运算符{{1标准库中的标签库应该是前一次调用delete[](void*)或者返回的值之一   标准库中的operator new[](std::size_t)

答案 1 :(得分:3)

由于你正在使用c ++,你可以在结构中放置一个析构函数来自动完成。还有其他方法,但这是最实用的:

struct gnt
{
    unsigned int* num;
    unsigned int size;
    bool negative;
    ~gnt() {delete [] num; }
};

我还建议有一个构造函数来确保num在初始化之前为null,因此析构函数在此之前将安全地工作:

struct gnt
{
    unsigned int* num;
    unsigned int size;
    bool negative;
    gnt() : num(NULL) {}
    ~gnt() {delete [] num; }
};

要在创建实例时分配或初始化时具有安全行为,您需要复制构造函数和赋值运算符。他们应该复制所有非动态成员的值,并创建具有相同大小和内容的num副本。在这种情况下,还建议初始化构造函数中的所有成员,因为size也应始终具有有效的内容以使其工作。如果您现在不想让事情太复杂,只需将它们设为私有,如果您尝试执行(不支持的)对象分配或复制,这将导致编译器咆哮:

struct gnt
{
    unsigned int* num;
    unsigned int size;
    bool negative;
    gnt() : num(NULL) {}
    ~gnt() {delete [] num; }
    private: gnt(const gnt&); gnt &operator = (gnt &);
};

正如其他人所说,一种替代方法是使用std :: vector而不是原始指针。这样,您无需担心解除分配:

struct gnt
{
    std::vector<unsigned int> num;
    unsigned int size;
    bool negative;
};

关于“我是否必须担心结构本身?”的问题,这取决于您如何创建其实例。如果是运营商新的,是的。如果没有,那么当他们作为任何其他变量超出范围时,他们将被解除分配。

最后,关于递归,IMO很少选择代码效率。只有当代码变得更简单/更清晰并且没有不利影响的危险(如堆栈溢出)时,才应使用递归。如果情况并非如此,我总是会选择迭代版本。

答案 2 :(得分:1)

递归的通常优点是简单和清晰(可能是针对问题的不同方法),通常不是速度。事实上,相反的情况恰恰相反:递归实现往往明显慢于迭代实现。现代硬件已经消除或大幅度降低了速度差异,但是递归实现比迭代对应更快仍然是相当不寻常的。

答案 3 :(得分:0)

free对任何指针都没问题,不管它是否是结构成员。如果您正在编写C代码,那么最好使用malloc()free()

对于递归与否,取决于上下文。一般来说递归是可以的。由于某些函数调用和参数传递开销,递归稍慢。递归的问题在于,如果你在递归级别非常深入(可能是1000次嵌套函数调用),你最终可能会填充堆栈。这会导致程序崩溃。