views:

169

answers:

5

I am using a function that returns a char*, and right now I am getting the compiler warning "returning address of local variable or temporary", so I guess I will have to use a static var for the return, my question is can I make something like if(var already set) return var else do function and return var?

This is my function:

char * GetUID()
{
   TCHAR buf[20];

   StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"), 
            someFunction());

   return buf;
}

And this is what I want to do:

char * GetUID()
{
   static TCHAR buf[20];

   if(strlen(buf)!=0) return buf;

   StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"), 
            someFunction());

   return buf;
}

Is this a well use of static vars? And should I use ZeroMemory(&buf, 20*sizeof(char))? I removed it because if I use it above the if(strlen...) my TCHAR length is never 0, should I use it below?

+3  A: 

It's OK if your code is single threaded. The buffer will be set to contain all zeros when the function is entered for the very first time, so there is no need to explicitly set its contents to zero. But these days all code eventually tends to become multi-threaded, so I would not do this, if I were you.

anon
You can still shoot yourself in the foot in single-threaded code. Simply call `GetUID()`, storing the pointer in a local variable. Then call it again storing the result in a second local variable. The second call just clobbered the value of the first, and no threads involved.
Fred Larson
@Fred He isn't storing a pointer.
anon
Personally, I never rely on the stack to be initialized to 0 as this code does... Maybe I'm just being paranoid.
dicroce
@dicroce: static and global variables aren't on the stack and they are always initialized to zero.
Zan Lynx
anon
I guess I was thinking along the same lines as Dima. If the OP really wants the same return value for each call, and it's not multi-threaded, this should work.
Fred Larson
+1  A: 

You could do that, but it won't be thread-safe. You should also be careful with what you do with the result, since you can not store it between subsequent calls to the function (without copying it, of course).

You should also initialize the static variable to the empty string.

Krumelur
+2  A: 

What you should do instead is allocate buf dynamically using new, and then return it. But be aware that the caller would be responsible for deallocating the memory.

Better yet, use std::string instead of char *.

Dima
Normally, I'd agree. But this won't address "caching" the result, as asked. The caller could free or delete the referenced memory, invalidating the cached result.
jmanning2k
For the OP's purposes - completely wrong.
anon
I don't think "caching" is the real issue here. It seems to me that flyout is just trying to get around the problem with returning a dangling pointer to a local array.
Dima
@dima Perhaps the use of the word "cache" in the question is misguiding us?
anon
@Neil I think it's misguiding some of us... :)
Dima
+4  A: 

The reason you're getting a warning is because the memory allocated within your function for buf is going to be popped off the stack once the function exits. If you return a pointer to that memory address, you have a pointer to undefined memory. It may work, it may not - it's not safe regardless.

Typically the pattern in C/C++ is to allocate a block of memory and pass a pointer to that block into your function. e.g.

void GetUID( char* buf )
{
    if(strlen(buf)!=0) return;

    StringCchPrintf(buf, 20*sizeof(char), TEXT("%s"), someFunction());
}

If you want the function (GetUID) itself to handle caching the result, then you can use a static, a singleton (OOP), or consider thread local storage. (e.g. in Visual C++)

__declspec(thread) TCHAR buf[20];
hemp
This is strictly a C pattern. In C++ you would of course use a `std::string` and be done with manual memory management.
Matthieu M.
@Matthieu M: I would agree with you, except most of the "C++" I've seen in the real world looks strikingly like C with additional scoping. The old memory management patterns are (all too often) still applied.
hemp
Yes, people code in C in the middle of C++, that's still C though, at least that's how I see it :)
Matthieu M.
A: 

This is how I would do it. It caches; it does not rely on the buffer being 0.

It does have the implicit assumption that 'buf' will be identical from thread to thread, which is not (to my knowledge) correct. I would use a global for that purpose.

//returns a newly allocated buffer, every time. remember to delete [] it.
char * GetUID()
{
   static TCHAR buf[20];
   static bool run = false;
   TCHAR ret_mem = new TCHAR[20];

   if(run) 
  { return ret_mem; }

  //do stuff to the buf
  //assuming - dst, src, size. 
  memcpy(ret_mem, buf, 20);

  run = true;
  return ret_mem;
}
Paul Nathan