C ++ Check if a pointer is passed, else create it?
Okay, I've seen this done somewhere before, where you have a function that takes a pointer parameter and returns a pointer.
However, you can choose not to pass a parameter and return a dynamically assigned pointer, but if you pass in a pointer, it will just fill it up instead of creating it on the heap. This is one function not overloaded.
My question is, how is this safely done?
I had a guess it was something like this:
point* funct(point *p = some_value)
{
if p == some_value
//create a point *p on the heap
else
//create use the given *p and fill it in
return p
}
Now I can't think if this is the right thing to do, and if that's what a good some_value might be? it cannot be NULL because when you pass a null pointer it will also be NULL and not sure if it is safe to have it greater than 0. Also you cannot have negative numbers on pointers, so what is a good safe value?
Any good way to do this, also PORTABLE across platforms?
EDIT:
Ok, maybe I didn't explain it correctly, basically I want the function to be used like this:
point *x;
point *y;
x = func();
func(y);
Not
x = func(NULL);
if i use NULL, i only get segmentation fault when i execute func (y);
The reason for this is:
either the user passes a pointer that he controls, for example, created on the stack, or the function returns a dynamic one if not specified. I don't want to force heap only return or accept only a pointer to be filled.
I know I've seen this before.
source to share
You have to ask yourself why passing NULL to us is giving you a seg error. This is of course not because NULL is not an appropriate value, it will be caused by what your code does when passing NULL. However, you chose not to display this code.
You probably stepped through this code in your debugger?
Also, don't use NULL in C ++. This is a macro and is open to incorrect redefinition. Use simple zero (0). The language places ensure that a null literal constant when converted to a pointer will not be a valid address. Probably your NULL macro is actually defined as null.
If you try to dereference a null pointer, you get an error.
source to share
The normal solution is to have "if NULL allocate", which is what "c" realloc does.
It sounds like you want a function that uses existing memory, if provided, or allocates it yourself. It's not clear what you should return if passed a valid pointer.
Should it return this pointer?
Or it should be null to ensure that there are no two copies of pointers per bit of memory - which will cause problems if freed.
It might be safer to pass a ** pointer to a function and require an argument - even if that argument is a null pointer.
source to share
Well, obviously if anyone ever had to call a (NULL) function, it would crash anyway. so why not have some_value = NULL to do
if(p==NULL){
p=dynamic_memory;
}
where dynamic_memory is allocated in the constructor (not thread safe!) or replaces dynamic_memory with a call to new
Edit:
Or. If you need to have 3 states in your function, one if no argument is specified, one for if a valid pointer is passed, and one for passing NULL, then you can use pointers for pointers.
as
void *func(void** p=NULL){
if(p==NULL) ...//user supplied no argument
if(*p==NULL) ...//user supplied NULL
else //user supplied valid pointer
This doesn't sound like what you want, but then people will need to pass pointers with & to your function .. ( &NULL
even valid?)
source to share
My guess would be more line by line:
point* funct(point *p = NULL)
{
if (p == NULL) {
// create a point *p on the heap
// and use it
return(p);
}
else {
//use the given *p and fill it in
return(NULL);
}
}
Not too sure if you have a pointer to your point object. It can be quite difficult to check, and checking the type of the passed object, i.e. Cover search using RTTI is not OO best practice.
source to share
something like that:
T* func(T* p) {
if(!p) {
p = new T;
}
// do whatever with p
return p;
}
then you can either do:
T* x = func(NULL);
// whatever
delete x;
or
T x;
func(&x);
EDIT:
There is a non-thread safe option that several libraries use. It basically works like this:
T* func(T* p) {
static T buf;
if(!p) {
p = buf;
}
// do whatever with p
return p;
}
then you can either do:
T* p = func(NULL);
or
T x;
T* p = func(&x);
There are often "reentrant" versions of these versions that are often tied to non-thread safe versions:
T* func(T* p) {
// behaves as above example, except now we can
// use func_r in a thread safe way if we need to
static T buf;
return func_r(p, buf);
}
T* func_r(T* p, T *buf) {
if(!p) {
p = buf;
}
// do whatever with p
return p;
}
source to share
You get an error when you call func (y) because y is not initialized. It contains random bits that indicate a random location in memory. You need to initialize y to NULL.
point *x, *y;
x = func();
y = NULL;
y = func(y); // so it can be deleted later you need to assign the return value
delete x;
delete y;
Why not do it? And avoid heap allocation entirely.
point x, y;
func(&x);
func(&y);
Or:
point *x;
point *y = new point();
x = func();
func(y);
delete x;
delete y;
As I said in the comment above, memory ownership obfuscates your function. Functions that dynamically allocate their results should do this every time or anytime. When they do this for a while, the potential for memory leaks is much higher.
Personally, I would go even further and avoid all distributions, pass by reference:
void func(point& p)
{
//do stuff
}
point x, y;
func(x);
func(y);
source to share
What is the problem with using NULL? This is a common way of processing. If you really need to distinguish between "caller passed nothing" and "caller passed NULL", use 0xFFFFFFFF
on a 32-bit system or 0xFFFFFFFFFFFFFFFF
on a 64-bit system.
point * funct(point * p = (point *)(-1))
{
if (p == (point *)(-1))
{
p = new point();
}
if (p == NULL)
{
// special case handling
return NULL;
}
// fill in p
return p
}
Listing "-1" will always be the maximum pointer value if you are in a two's complement architecture. Feel free to substitute a C-style listing with a reinterpretation if you like.
source to share
However, you can choose not to pass a parameter and return a dynamically assigned pointer, but if you pass in a pointer, it will just fill it up instead of creating it on the heap. This is one function not overloaded.
Instead of using default arguments, you can overload the function:
point* funct(point *p = some_value)
{
// fills p
}
point* funct()
{
return funct(new point());
}
It might not be the right way, but somewhere I think there is a function in the Linux libraries that works exactly the same as above, not sure how it stands out internally though
I don't know of any such function. I would guess that you are thinking of realloc , which takes a pointer and size_t
then decides whether to allocate memory, allocated memory, or free memory.
Now I can't think if this is the right thing to do, and if that's what a good some_value might be? it cannot be NULL because when you pass a null pointer it will also be NULL and not sure if it is safe to have it greater than 0. Also you cannot have negative numbers on pointers, so what is a good safe value?
I think your confusion stems from a fundamental misunderstanding of the pointer NULL
.
Note:
int x = 5;
int* px = &x;
int* p_null = NULL;
int* p;
int* p_new = new int();
px
points to x, so it doesn't NULL
. p_null
begins life as NULL
, which means that it points to nothing.
I think you are using the term null pointer to refer to something like p
or p_new
. However, while it p
does not indicate a valid object, it has not been set to either NULL
. It is effectively an invalid pointer, and there is no portable way of saying that it is invalid (on some machines it might be right if something is clearly invalid , but even then it is impossible to catch all invalid pointers - see the note - and you probably are not want the second half anyway ).
And p_new
points to a valid heap address. It is not NULL. It is not empty. In fact, it new
initializes int
to 0.
In other words, NULL
is the value you pass to functions that expect a pointer to tell them that you don't have a pointer. What it is. And there is no idea of a null pointer. Dangling pointers (either uninitialized pointers, or memory pointers that you don't have access to) are not NULL
, because if they were NULL
, they won't dangle. And it is not possible to validate pointers in all cases to determine if they are valid.
Note
Consider:
int* p_new2 = new int();
delete p_new2;
delete
does not install p_new2
in NULL
. Therefore, after delete
, it p_new2
will have an address in the correct range for a valid pointer (which means that the Windows VirtualQuery method will be "sure the pointer can point to it"), but will not have permission to actually dereference that memory address.
NOTE 2
This is a terribly bad idea, don't do this:
int* funct()
{
int y = 5;
return &y;
}
int* x = funct();
y
ceases to exist upon return funct()
. Thus, a pointer to y
, which funct()
points you to something that doesn't exist. This way you end up with a dangling pointer. You don't talk about it, but this is a common mistake and it will bite you.
source to share
Ok, I decided not to use this idiom seems bad, although I know that one of the unix or linux system libraries had such a feature.
I am not answering my own question, but I just remembered the ctime idiom, which is probably a much safer way to do what I want. I'm talking about the time () function.
Where it takes a pointer or returns an object by value.
I think it probably even gives better flexibility when returning on cost, heap or stack allocation with a user-controlled pointer. I don't know why I hadn't thought about this before.
What are you guys thing, the ctime idiom is much better?
Edit: Does this idiom use NULL?
source to share