我是结构新手所以请耐心等待。我写了一个名为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个条目之间)并且似乎没有任何时间优势...递归代码比其对应的短。
感谢您的任何意见。
答案 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次嵌套函数调用),你最终可能会填充堆栈。这会导致程序崩溃。