don't click here

Programming tips & tricks

Discussion in 'Technical Discussion' started by GerbilSoft, Jul 24, 2014.

  1. GerbilSoft

    GerbilSoft

    RickRotate'd. Administrator
    2,971
    76
    28
    USA
    rom-properties
    Occasionally I find some useful tricks when programming stuff that can improve performance or otherwise enhance the resulting software. This thread will be used to collect assorted tips and tricks, and you can post your own interesting stuff here too.

    Today's tip: MSVC's cout is ridiculously slow. It turns out this is because MSVC doesn't normally buffer cout (and probably cerr) by default.

    Solution: Add this to the beginning of your program:
    Code (Text):
    1.  
    2. if (setvbuf(stdout, 0, _IOLBF, 4096) != 0) {
    3.     abort();
    4. }
    5. if (setvbuf(stderr, 0, _IOLBF, 4096) != 0) {
    6.     abort();
    7. }
    8.  
    This sets a 4K line buffer for both stdout and stderr. I ran the test program listed at the below MS Connect page, and found that on MSVC 2010, this improves printf() performance by around 1x-1.5x, and cout performance by over 30x. (MSVC 2013 performance with setvbuf() was slightly faster than MSVC 2010, but interestingly it was slower than 2010 if setvbuf() wasn't used.)

    (Reference: https://connect.microsoft.com/VisualStudio/feedback/details/642876/std-wcout-is-ten-times-slower-than-wprintf-performance-bug-in-c-library )

    [NOTE: The referenced page also has a tip for using cout.pubsetbuf(), but on MSVC 2013 at least, if the buffer isn't flushed using endl, MSVCP120 may overflow the buffer, resulting in a crash. It doesn't improve performance that much compared to setvbuf() anyway, so don't bother using it.]

    I haven't tested mingw gcc or Linux gcc yet, but I would assume both of those properly buffer stdout and cout. (...actually, considering that's a property of the C library, it'd more appropriately be MSVCRT [which doesn't buffer stdout] and glibc [which might?].)

    EDIT: MSVC doesn't actually support line buffering. Enabling line buffering will actually enable full buffering, which may be problematic since printf() on MSVC 2010 doesn't seem to flush the buffer after a newline. endl does flush the buffer. If you're using printf, you can flush the buffer manually using fflush(stdout), but that isn't optimal.
     
  2. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    In C++, you can get the number of elements in an array by using:
    Code (Text):
    1. template <typename T, size_t N>
    2. inline size_t LengthOfArray(const T(&)[N])
    3. {
    4.     return N;
    5. }
    Similarly, the total size of an array can be retrieved with:
    Code (Text):
    1. template <typename T, size_t N>
    2. inline size_t SizeOfArray(const T(&)[N])
    3. {
    4.     return N * sizeof(T);
    5. }
     
  3. Is there any significant difference between this and sizeof(array)/sizeof(array[0])?

    Code (Text):
    1. #include <stdio.h>
    2.  
    3. template <typename T, size_t N>
    4. inline size_t LengthOfArray(const T(&)[N])
    5. {
    6.     return N;
    7. }
    8.  
    9. size_t pointer_sizeof(int array[])
    10. {
    11.     return sizeof(array)/sizeof(array[0]);
    12. }
    13. #if 0
    14. // doesn't compile: no matching function for call to 'LengthOfArray(int*&)'
    15. size_t pointer_template(int array[])
    16. {
    17.     return LengthOfArray(array);
    18. }
    19. #endif
    20.  
    21. int main(void)
    22. {
    23.     int array[1000];
    24.  
    25.     printf("%u\n", sizeof(array)/sizeof(array[0]));
    26.     printf("%u\n", LengthOfArray(array));
    27.     printf("%u\n", pointer_sizeof(array));
    28.     // printf("%zu\n", pointer_template(array));
    29.  
    30.     return 0;
    31. }
    gives:

    1000
    1000
    1

    I suppose it has the benefit of type checking, but sizeof works in straight C too.
     
  4. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    The only difference is type checking, it prevents accidentally converting an array to a pointer as in your pointer_sizeof function.
     
  5. Billy

    Billy

    RIP Oderus Urungus Member
    2,118
    178
    43
    Colorado, USA
    Indie games
    If you're using C++11, look into shared_ptr. It can very verbose in terms of code, but pretty handy in the right situation.

    Making a game and you need to detect collisions between a lot of objects? Use quadtrees.

    A better random number generator for C++: here.

    Here's one from me: Line of sight testing in a 2D tile based game. (Let me know if there's any errors with this one, please)
     
  6. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    I use shared_ptr to manage a block of data allocated by a class' initializer in the SADX Mod Loader, so it gets deleted automatically when the last instance of the object does. It's not ideal, since other code could hold pointers into the block of data when the object is deleted, but I think it's better than requiring the client to manually delete the data.
     
  7. GerbilSoft

    GerbilSoft

    RickRotate'd. Administrator
    2,971
    76
    28
    USA
    rom-properties
    Today's tip: Don't pass std::string (or any other large object) by value.

    Code (Text):
    1.  
    2. int someFunction(std::string x)
    3. {
    4.     // blah
    5. }
    6.  
    If your function doesn't modify the string, then it's better to pass it by const reference. gcc uses copy-on-write strings, so it has to increment a reference counter every time you pass a string by value. MSVC, on the other hand, uses "short strings", which requires copying at least 28 bytes (32-bit) or 40 bytes (64-bit) every time you pass a string by value. This isn't including the string data itself, which is either stored within the string object if it's 15 bytes or less, or allocated separately on the heap if it's larger than 16 bytes.

    Do this instead:

    Code (Text):
    1.  
    2. int someFunction(const std::string &x)
    3. {
    4.     // blah
    5. }
    6.  
    This is effectively passing a const pointer that works the same way as a regular object.

    Supposedly C++ 2011 eliminates the need for passing by const reference by using "move semantics", but it hasn't been adopted much outside of e.g. libstdc++ and boost. I'd recommend using const reference anyway, since it also prevents accidental string overwrites.