0

I have an integer pointer as a default function parameter. If it is not null, I want to assign some value, maybe every 10th line in 200 lines. With standard check before every assignment, my code would easily get big and harder to read. (And by that I mean source file length and readability, not binary size.)

Is it good practice to replace this:

// Previous statement
// Use to put empty line here
if(ptr)
    *ptr = val;
// Empty line also here
// Next statement

with this:

// Previous statement
assignIfNotNull(ptr, val);
// Next statement

and put if in function?

inline void assignIfNotNull(int *ptr, int val)
{
    if(ptr)
        *ptr = val;
}

Now, I seem to be meticulous, but this will save 3 lines each use. Maybe not the worst thing in my programming style, made by improvisation as I learn alone. I want to suppress it, ask and keep up with standard. (I couldn't find this anywhere.)

Thanks in advance.

LogicStuff
  • 19,397
  • 6
  • 54
  • 74
  • 4
    Second version is wrong. You are passing the pointer by value you need either a double pointer or pass the pointer by reference. – 101010 Jul 31 '14 at 18:58
  • 10
    @40two The assign is *ptr = ..., it's fine –  Jul 31 '14 at 19:00
  • @DieterLücking apologies didn't notice that :( Please disregard my comment Dieter is right. – 101010 Jul 31 '14 at 19:01
  • I personally would not do this, because the API would not get much use. I would rather author tighter code that skips over any checking when I enter a section of code I know the pointer should be valid, rather than use an API to set the value that keeps doing needless checking. – jxh Jul 31 '14 at 19:06
  • Without support of some edit tools the assignIfNotNull needs more typing than the if version. Besides that, it is a pure convenience function. Even having a good name, you have to lookup (know) the function before using it (I would not do it, unless it is used locally in some source file) –  Jul 31 '14 at 19:09
  • By the way, you are only saving the *amount of lines typed*. The amount of code generated will be the same. The amount of time you save may be wasted on posting questions on StackOverflow, so it is a moot point. – Thomas Matthews Jul 31 '14 at 19:34
  • Maybe you should change your perspective. At my shop, if the pointer is null we call a system failure function. This handles the issue before any dereferencing can take place. Also consider using references instead of pointers. – Thomas Matthews Jul 31 '14 at 19:39

2 Answers2

1

C# null coalescing operator equivalent for c++ asks nearly exactly your question, but do not expect to find some breakthrough solution - there are just some variations on ternary operator,templates and Macros:

ptr = (ptr != null ? ptr : MY_DEFAULT)

//------------------- or as function
template<class T>
GetValueOrDefault(T* value, T* defaultValue) // or put your own types
{
    return value != null ? value : defaultValue;
}

ptr = GetValueOrDefault(ptr, MY_DEFAULT);

//------------------- or as macro

#define GET_VALUE_OR_DEFAULT(value, defaultValue) (value != null ? value : defaultValue)

ptr = GET_VALUE_OR_DEFAULT(ptr, MY_DEFAULT);

//------------------- or like this macro

#define VALUE_OR_DEFAULT(value, defaultValue) value = (value != null ? value : defaultValue)

VALUE_OR_DEFAULT(ptr, MY_DEFAULT);

But there are some points you should consider:

  1. Do not imagine a problem when it isn't there - a lot of checks and reinitialization are perfectly viable for some APIs - just take a look at WINAPI
  2. Are you sure that this variable should be overwritten? May be you could rewrite your function or API to not overwrite it.
  3. You may also consider to use some temporary variable in place of ptr - it won't solve the problem, just turn it upside down, but this could possibly improve overall comprehensibility of your function and remove checks:

      char* tempPtr = ptr;
      retCode = RandomlyNullifyThePtr(&tempPtr); // RandomlyNullifyThePtr can nullify the ptr it gets ,
      // but it won't nullify the ptr in calling function.
    
  4. If you are having problems with holding your entire function in conscience then it is direct sign that it should be refactored - divided into smaller pieces, where such checks may become unnecessary:

      retCode = CompletePart1(ptr); // CompletePart1 can nullify the ptr it gets, 
      // but it won't nullify the ptr in calling function.
      ...
      retCode = CompletePart2(ptr);
    
Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
  • Another consideration is using references instead of pointers. With a reference, the object is guaranteed to exist. A pointer can point to an invalid location and still be nonzero or non-null. – Thomas Matthews Jul 31 '14 at 19:37
1

You could go:

T dummy;
if ( !ptr ) 
    ptr = &dummy;

at the start; and then you can safely write *ptr = whatever; later without needing the null check.

If the original value of ptr is important you could call the parameter orig_ptr or something.

M.M
  • 138,810
  • 21
  • 208
  • 365