Reputation: 103
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.
Upvotes: 1
Views: 335
Reputation: 16049
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.
Upvotes: 3
Reputation: 206566
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 operatornew(std::size_t)
oroperator new(std::size_t, const std::nothrow_-t&)
in the standard library, and the value supplied to operatordelete[](void*)
in the standard library shall be one of the values returned by a previous invocation of eitheroperator new[](std::size_t)
oroperator new[](std::size_t, const std::nothrow_t&)
in the standard library.
Upvotes: 3
Reputation: 2472
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.
Upvotes: 0
Reputation: 490408
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.
Upvotes: 1