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.

+2


source to share


13 replies


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.

+1


source


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.

+8


source


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?)

+3


source


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.

+3


source


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

      

+2


source


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

      

+2


source


You have to pass it NULL (null by default ...) if you want to allocate, and pass a null pointer if you want to fill.

As jeffamaphone commented there is a difference between a null pointer and NULL, use your conditional statements to check if it is a null pointer or NULL

+1


source


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.

+1


source


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.

+1


source


The default is the default. There is no such thing as missing a value here. This can only happen with counting variable parameters, but that's a different story.

What is a null pointer?

0


source


You are looking for:

point* funct(point *p = some_value)
{
 if (p == NULL)
   return NULL;

 if (p == some_value) 
   p = new point;

   return p;
}

      

0


source


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?

0


source


If you really want to break them up this way, you cannot accidentally provide a default function, you must overload functions.

point* funct() {
    //alocate a point* p here
    return funct(p);
}

      

and

point* funct(point *p) {
    //do stuff
}

      

0


source







All Articles