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

发布于 2024-12-14 15:26:27 字数 1229 浏览 2 评论 0原文

我对结构很陌生,所以请耐心等待。我编写了一个名为 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 个条目之间),似乎在时间上没有任何优势......不过,递归代码比其对应代码短。

感谢您的任何意见。

I'm new to structures so please bear with me. I wrote a structure called gnt containing an integer pointer, an integer, and a boolean:

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

Because I am allocating arbitrary length int arrays to various gnt variables (ie. k.num = new int*[j]) (for some value j), I need to free them somehow. I am not sure how to do that. Do I simply use delete[] k.num; (where k is a gnt)? Do I have to worry about the structure itself?

Also, as a side question, I wrote a recursive function to multiply out items in a list:

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

Will this give any advantage over doing it without recursion? I tested with various sized lists (between 10 - 10000 entries) and there doesn't seem to be any advantage time wise... The recursive code is shorter than its counterpart though.

Thanks for any input.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

痴骨ら 2024-12-21 15:26:27

由于您使用的是 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: :向量而不是原始指针。这样,您就不需要担心释放:

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

关于“我是否必须担心结构本身?”的问题,这取决于您如何创建其实例。如果是 new 操作员,是的。如果不是,当它们像任何其他变量一样超出范围时,它们将被释放。

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

Since you're using c++, you can put a destructor in the struct to do that automatically for you. There are other ways, but this is the most practical:

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

I'd also suggest to have a constructor to make sure that num has null until it's initialized, so the destructor will work safely before that:

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

To have a safe behavior when instances are assigned or initialized when created, you need the copy constructor and assignment operator. They should copy the values of all the non-dynamic members, and create a duplicate of num with the same size and contents. In such case, it'd be also recommended to initialize all the members in the constructor, because size should also always have a valid content for that to work. If you don't want to complicate things too much now, just make them private, this will cause the compiler to bark if you try to do an (unsupported) object assignment or copy:

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

As others suggested, one alternative is to use std::vector instead of a raw pointer. That way, you don't need to worry about deallocations:

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

About the question "do I have to worry about the structure itself?", that depends on how you created its instances. If it was with operator new, yes. If not, they'll be deallocated when goin out of scope as any other variable.

Finally, about the recursion, IMO rarely the choice is about code efficiency. You should use recursion only if the code becomes simpler/cleaner AND there is no danger of adverse effects (like stack overflow). If that's not the case, I'd always go for the iterative version.

百合的盛世恋 2024-12-21 15:26:27

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

您使用 new [] 分配了成员 k.num,因此您应该仅为它调用 delete []

另外,您可以使用 std::vector 而不用自己进行内存管理(除非这是一些限制您这样做的蹩脚分配)


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

如果释放函数因抛出异常而终止,则行为未定义。提供给释放函数的第一个参数的值可以是空指针值;如果是这样,并且如果释放函数是标准库中提供的函数,则调用无效。否则,提供的值
标准库中的运算符 delete(void*) 应是先前调用运算符 new(std::size_t)返回的值之一标准库中的operator new(std::size_t, const std::nothrot_-t&),以及提供给标准库中的operatordelete[](void*)的值应是其中之一先前调用 operator new[](std::size_t)
标准库中的operator new[](std::size_t, const std::nothro_t&)

Follow the Rule:
You should pass the same address to delete[] that you received from new[].
If You allocated only a member on freestore, so you would need to deallocate only that.

You allocated the member k.num using new [], so yes you should call delete [] only for it.

Also, You can use std::vector instead of doing the memory management by yourself(unless this is some crappy assignment which restricts you from doing so)


For Standerdese Fans:
Standard C++03 § 3.7.4.2-3:

If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. Otherwise, the value supplied
to operator delete(void*) in the standard library shall be one of the values returned by a previous invocation of either operator new(std::size_t) or operator new(std::size_t, const std::nothrow_-t&) in the standard library, and the value supplied to operator delete[](void*) in the standard library shall be one of the values returned by a previous invocation of either operator new[](std::size_t) or
operator new[](std::size_t, const std::nothrow_t&) in the standard library.

不甘平庸 2024-12-21 15:26:27

递归的通常优点是简单和清晰(并且可能是解决问题的不同方法),通常不是速度。事实上,过去的情况恰恰相反:递归实现往往比迭代实现慢得多。现代硬件已经消除或大大减少了这种速度差异,但递归实现比迭代实现更快仍然是相当不寻常的。

The usual advantage of recursion is simplicity and clarity (and possibly a different approach to a problem), not normally speed. In fact, rather the opposite used to be true: recursive implementations tended to be noticeably slower than iterative ones. Modern hardware has eliminated or drastically reduced that speed differential, but it would still be fairly unusual for a recursive implementation to be faster than an iterative counterpart.

浅语花开 2024-12-21 15:26:27

free 适用于任何指针,无论它是否是结构成员。如果您正在编写 C 代码,也许使用 malloc()free() 会更好。

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

free is fine on any pointer disregarding the fact it is a structure member or not. If you are writing C code maybe it would be better to use malloc() and free().

For recursion or not it depends on the context. Generally speaking recursion is ok. Recursion is slightly slower because of some function calling and parameter passing overhead. The problem with recursion is that if you go very deep in recursion level (maybe 1000 nested function call) you could end up filling the stack. This would cause the program to crash.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文