As a C++ programmer I sometimes need deal with memory buffers using techniques from C. For example:
char buffer[512];
sprintf(buffer, \"Hello %s!\", userName.c_s
Is passing the buffer as &buffer[0] better programming style than passing buffer? (I prefer &buffer[0].)
&buffer[0]
makes the code less readable to me. I have to pause for a second and wonder why someone used it instead of just passing buffer
. Sometimes you have to use &buffer[0]
(if buffer
is a std::vector
), but otherwise, stick with the standard C style.
Is there a maximum size that is considered safe for stack allocated buffers?
I doubt there's any practical limit, as long as you're using the stack reasonably. I've never had any problems in my development.
If I'm reading MSDN correctly, threads on Windows default to 1MB of stack size. This is configurable. Other platforms have other limits.
Is static char buffer[N]; faster? Are there any other arguments for or against it?
On the one hand, it might reduce the need to commit memory pages for stack, so your app might run faster. On the other hand, going to the BSS segment or equivalent might reduce cache locality compared to the stack, so your app might run slower. I seriously doubt you'd notice the difference either way.
Using static
is not threadsafe, while using the stack is. That's a huge advantage to the stack. (Even if you don't think you'll be multithreaded, why make life harder if that changes in the future?)
When using static buffers you can have your function return have the const char * return type. Is this a good idea? (I do realize that the caller will need to make his own copy to avoid that the next call would change the previous return value.)
Const correctness is always a good thing.
Returning pointers to static buffers is error-prone; a later call might modify it, another thread might modify it, etc. Use std::string
instead or other auto-allocated memory instead (even if your function needs to deal internally with char buffers such as your GetCurrentDirectory
example.)
What about using static char * buffer = new char[N]; and never deleting the buffer? (Reusing the same buffer each call.)
Less efficient than just using static char buffer[N]
, since you need a heap allocation.
I understand that heap allocation should be used when (1) dealing with large buffers or (2) maximum buffer size is unknown at compile time. Are there any other factors that play in the stack/heap allocation decision?
See Justin Ardini's answer.
Should you prefer the sprintf_s, memcpy_s, ... variants? (Visual Studio has been trying to convince me of this for a long time, but I want a second opinion :p )
This is a matter of some debate. Personally, I think these functions are a good idea, and if you're targeting Windows exclusively, then there's some benefit to taking the preferred Windows approach and using those functions. (And they're fairly straightforward to reimplement if you later need to target something other than Windows, as long as you don't rely on their error-handling behavior.) Others think that the Secure CRT functions are no more secure than properly used C and introduce other disadvantages; Wikipedia links to a few arguments against them.
buffer
is more terse but if it were a vector
, you'd need to do &buffer[0]
anyway.std::string
. If performance becomes a problem, you'd be able to reduce dynamic allocations by just returning the internal buffer. But the std::string
return interface is way nicer and safer, and performance is your last concern.std::vector
, you should never be doing any raw allocation! If you're putting yourself into a position where you might leak (because it needs to be done explicitly), you're doing it wrong.std::string
, std::stringstream
, std::copy
, etc.Code for dynamic stack/heap buffer:
template<size_t BUFSIZE,typename eltType=char>
class DynamicBuffer
{
private:
const static size_t MAXSIZE=1000;
public:
DynamicBuffer() : m_pointer(0) {if (BUFSIZE>=MAXSIZE) m_pointer = new eltType[BUFSIZE];}
~DynamicBuffer() {if (BUFSIZE>=MAXSIZE) delete[] m_pointer;};
operator eltType * () { return BUFSIZE>=MAXSIZE ? m_pointer : m_buffer; }
operator const eltType * () const { return BUFSIZE>=MAXSIZE ? m_pointer : m_buffer; }
private:
eltType m_buffer[BUFSIZE<MAXSIZE?BUFSIZE:1];
eltType *m_pointer;
};
Is passing the buffer as &buffer[0] better programming style than passing buffer? (I prefer &buffer[0].)
It depends on the coding standards. I personally prefer: buffer + index
instead of &buffer[index]
but it's a matter of taste.
Is there a maximum size that is considered safe for stack allocated buffers?
It depends on the stack size. If the amount of stack needed for your buffer exceeds the amount available on the stack, it result a stack-overflow.
Is static char buffer[N]; faster? Are there any other arguments for or against it?
Yes, it should be faster. See also this question: Is it bad practice to declare an array mid-function
When using static buffers you can have your function return have the const char * return type. Is this a good idea? (I do realize that the caller will need to make his own copy to avoid that the next call would change the previous return value.)
Not sure what static means in this case but:
If variable is declared on stack( char buf[100]
):
You should not return references to stuff that is declared on the stack. They will be trashed at next function call/declaration (e.g. when the stack is used again).
If the variable is declared as static static
it will make your code non-reentrant. strtok is an example in this case.
What about using static char * buffer = new char[N]; and never deleting the buffer? (Reusing the same buffer each call.)
It is a possibility, though not recommended because it makes your code non-reentrant.
I understand that heap allocation should be used when (1) dealing with large buffers or (2) maximum buffer size is unknown at compile time. Are there any other factors that play in the stack/heap allocation decision?
Stack size of the running thread is too small to fit stack declaration (previously mentioned).
Should you prefer the sprintf_s, memcpy_s, ... variants? (Visual Studio has been trying to convince me of this for a long time, but I want a second opinion :p )
If you want your code to be portable: No. But the effort in creating a portable macro is quite small in this case:
// this is not tested - it is just an example
#ifdef _WINDOWS
#define SPRINTF sprintf_s
#else
#define SPRINTF sprintf
#endif
Stay away from static buffers if you ever want to use your code re-entrantly.
use snprintf() instead of sprintf() so you can control buffer overruns.
You never know how much stack space is left in the context of your call -- so no size is technically 'safe'. You have a lot of headroom to play with most of the time. But that one time will get you good. I use a rule of thumb to never put arrays on the stack.
Have the client own the buffer and pass it and its size to your function. That makes it re-entrant and leaves no ambiguity as to who needs to manage the life of the buffer.
If you're dealing with string data, double check your string functions to make sure they terminate especially when they hit the end of the buffer. The C library is very inconsistent when it comes to handling string termination across the various functions.
If a function gives you a method of knowing how many characters it will return, use it. Your sample GetCurrentDirectory is a good example:
DWORD length = ::GetCurrentDirectory(0, NULL);
Then you can use a dynamically allocated array (either string or vector) to get the result:
std::vector<TCHAR> buffer(length, 0);
// assert(buffer.capacity() >= length); // should always be true
GetCurrentDirectory(length, &buffer[0]);