C ++ Tips and Tricks, tipsandtricks

Source: Internet
Author: User

C ++ Tips and Tricks, tipsandtricks

I sorted out the skills and suggestions I encountered in the C ++ project code.

0x00 uses macro definition.
It is often seen that programmers use the enum value to print the debugging information and want to print the character meanings of numbers. I have seen someone write this Code if (today = MONDAY) return "MONDAY"; generally, there are many error codes. switch-case should be used instead of if-else. Because if-else is worse than N times, switch-case is worse than lgN times. Here we use the macro to introduce the code. In addition, the search is removed and the corresponding string is indexed directly.

enum Day{    SUNDAY = 0,    MONDAY,    TUESDAY,    WEDNESDAY,    THURSDAY,    FRIDAY,    SATURDAY,    COUNT};const char* toString(Day day){#define CODE(code) array[static_cast<uint32_t>(code)] = #code    const char* array[COUNT];    CODE(SUNDAY);    CODE(MONDAY);    // ...#undef CODE    assert(0 <= day && day < COUNT);    return array[day];}

Someone said that the array will be initialized every time it is run. Yes, you can use the static variable to initialize it only once. In the generated assembly code, a bit is set to check whether it has been initialized and jump accordingly.
Of course, if you want to execute a piece of code or a function once. That is to say, let the function have the effect of static variables, but not add the static keyword (the static function indicates that the scope is only visible in this file). You can write it like this:

void do_something(){    std::cout<< "hello world\n";}bool run_once(){    do_something();    return true;}int main(){    static bool unused = run_once();    return 0;}

In this way, you can use it. With the lambda function of C ++ 11, you do not need to write any additional functions!

Static bool unused = [] ()-> bool {do_something (); return true ;}();

The simplest lambda function declares [] () {}; to call this function is [] () {} ();. How are you doing? Is it fun?


0x01 efficiency improvement: Use a temporary register variable to reduce the number of member variable reads and writes.
During Gameloft game development, you often need to consider how to improve the game performance. The iPhone and iPad have a very good hardware level and different Android hardware levels. Therefore, the gaming experience from iOS to Android needs to be considered. Let's talk about a problem I encountered in the game. There is an array values in the class. We cache its calculation result mTotal, so that it does not need to be calculated every frame.

for(int i = 0; i < count; ++i)    mTotal += values[i];////////////////////////////////register int64_t total = 0;for (int i = 0; i < count; ++i)    total += values[i];mTotal = total;

The functions of several lines of code are the same, but the following steps are faster. The following uses a stack temporary variable (using register or allocating it to a register), which does not need to be read or written in every loop.Member variables, But the last write after the computation. Some may still do not understand. You can decompile the code into an assembly and view the analysis. Whether read or write, you can first find the object and then find the member variable.



0x02 simulate the startWith method of String in Java.

#include <string>std::string haystack("malicious");std::string needle("mali");
bool startWith(const std::string& haystack, const std::string& needle){    return haystack.compare(0, needle.length(), needle) == 0;}

The startWith method is not provided in C ++, so the Java programmer wants to find this function when converting C ++ and processing strings. Developers of other languages will have similar experiences. In the preceding example, haystack and needle are used to apply strstr parameter names. After man strstr, char * strstr (const char * haystack, const char * needle );. In addition, the length of std: string can be set to length () or size (), but it is best to use length () Because size () it is a concept used in STL to show differences.



0x03 scanf and printf Functions
When reading a string, use a comma to stop it. You can write it as follows: scanf ("% [^,] \ n", str );. But if there are multiple strings and the previous characters are ignored, how can we write them? For example, if I want to get the last name of "Taylor Swift", this is generally the case. scanf ("% s", temp, last_name); this occupies a temporary variable, change to scanf ("% s", last_name); scanf ("% s", last_name); you need to call the scanf function twice, the best answer is scanf ("% * s % s", last_name );. Yes. If you want to ignore an input, you can use * after % *.

Before writing data, the buffer size cannot be determined. How can I write it? Printf family functions are all used for printing. Few people can say that they have returned values, and the return value is the number of written characters. Here, the return value comes in handy.
Callingstd::snprintfWith zerobuf_sizeAnd null pointerbufferIs useful to determine the necessary buffer size to contain the output:

const char *fmt = "sqrt(2) = %f";int sz = std::snprintf(nullptr, 0, fmt, std::sqrt(2));std::vector<char> buf(sz + 1); // note +1 for null terminatorstd::snprintf(&buf[0], buf.size(), fmt, std::sqrt(2));

Visual C ++ has not previously provided the snprintf function, but replaced it with _ snprintf and _ snprintf_s. Looks like, but the completed functions are somewhat different from the C language standard. It is not added until Visual Studio 2015. _ Snprintf does not write the \ 0 character when writing overflow. _ snprintf_s improves security, but returns-1 when overflow occurs, it is not the length of the characters written to the returned result as required by the standard.

#ifndef COMPILER_H_#define COMPILER_H_#include "stdio.h"#include "stdarg.h"/*    Microsoft has finally implemented snprintf in VS2015 (_MSC_VER == 1900).    Releases prior to Visual Studio 2015 didn't have a conformant implementation.     There are instead non-standard extensions such as _snprintf() (which doesn't     write null-terminator on overflow) and _snprintf_s() (which can enforce     null-termination, but returns -1 on overflow instead of the number of     characters that would have been written).*/#if defined(_MSC_VER) && _MSC_VER < 1900#define snprintf c99_snprintf#define vsnprintf c99_vsnprintfinline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap){    int count = -1;    if (size != 0)        count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);    if (count == -1)        count = _vscprintf(format, ap);    return count;}inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...){    int count;    va_list ap;    va_start(ap, format);    count = c99_vsnprintf(outBuf, size, format, ap);    va_end(ap);    return count;}#endif#endif /* COMPILER_H_ */


0x04 type conversion.
In the days of Gameloft, Code Review is regularly performed every month, and the results will be reported to you. Many people are reluctant to write C ++ type conversion because it is a little long and convenient without the brackets in C language. As a result, I developed the habit of correctly using C ++ conversions when writing C ++ code, and the current compiler will have the completion prompt function, you do not need to enter a complete keyword. In addition, the RTTI and exception functions of C ++ are avoided in the game. The RTTI overhead is large, and the previous exception handling in C ++ is simply a weakness. Here, the contradiction arises. dynamic_cast should be used according to the former (C ++ cast), and the latter (RTTI used) should not be used. Therefore, the following code is used to detect the correct type during debugging of the debug version. The release version is strongly converted. Many objects inherit from Entity, so the Creature class uses the so-called CREATURE_CAST macro, which is actually
# Define CREATURE_CAST (entity) downcast <Creature *> (entity)

template <typename To, typename From>To downcast(From p){#ifdef DEBUG    To to = dynamic_cast<To>(p);    assert(to != nullptr);    return to;#else    return static_cast<To>(p);#endif}

 

0x05 jump to new gameplay.
If both int a and B values are met, execute a statement. Most people write this statement: if (a> 0 & B> 0) do_something ();
When I was reading the code, I saw a very good way of writing and forgot the source. Statement: if (a | B)> 0) do_something ();
A jump command is missing. You can feel it.
If (isGood) return true; else return false; in this code, you can simply write return isGood.


Migration between 0x06 char * and std: string.

<String. h >=> <string> strlen (str) => str. size () strcmp (s1, s2) => s1.compare (s2) strcat (s1, s2) => s1 + = s2strcpy (s1, s2) => s1 = s2strstr (s1, s2) => s1.find (s2) strchr (str, ch) => str. find_first_of (ch)
Strrchr (str, ch) => str. find_last_of (ch) strspn (s1, s2) => s1.find _ first_not_of (s2) s1 = strdup (s2) => s1 = s2



0x06 faster cycles.
There is a faster loop, not parallel computing. In fact, I want to say that some poorly written code will lead to a lower speed. Writing new code by hand makes it easy for the code to meet functional requirements. It is rare to write better code like a craftsman. I have seen the for (int I = 0; I <strlen (str); I ++) code written in this way, which is functionally correct, but: first, if str is too long, efficiency is not ideal, because it calculates the length of each loop. Second, although the compiler may optimize I ++, it is best to use prefix auto-increment ++ I. Third, for integer comparison with incorrect type, I is int type, while strlen returns size_t type. Then he changes it to this way. size_t len = strlen (str); for (size I = 0; I <len; ++ I) extracts the length, an additional variable is used. Then I told him that it could be written like this: for (size I = 0, len = strlen (str); I <len; ++ I) or for (const char * p = str; * p! = '\ 0'; ++ p ).
When reading STL data structures, be careful with the overhead of calling constructors. One person in the project really liked the for loop with a colon (that is, for_each), which is very good and conforms to the Information Hiding idea of C ++. I just want to traverse it. You don't need to tell me clearly that it is from the First Auto-increment iteration to the last one. But when he wrote it, it was like this:
std::vector<Creature> creatures;for(const Creature creature: creatures)    creature.roar();

At first glance, nothing. I reminded him that the reference should be used here, for (const Creature&Creature: creatures) to avoid the overhead of calling the copy constructor, which is the same as passing the value of the function and passing the reference.


0x07 is there a function similar to std: binary_search? What I need is the return iterator, instead of simply telling me whether the searched element exists.
There seems to be no such function in STL, but you can use std: lower_bound, std: upper_bound or std: pai_range.
template<class Iter, class T>Iter binary_find(Iter begin, Iter end, T value){    // Finds the lower bound in at most log(last - first) + 1 comparisons    Iter it = std::lower_bound(begin, end, value);    if (it != end && !(value < *it))        return i; // found it    else        return end; // not found}

The function used by STL to get the find name is returned to the iterator.
Note: Here is the template function. Do not use * it = value. Use it! (Value <* I ). The reason is that std: lower_bound uses <, that is, strict weak order relationship. The type T here can not be equal to =. Equality and equivalence cannot be confused. You can view 19 of Scott Meyers's book valid tive STL, the difference between equality and equivalence.
I planted it too. The unordered_map class template declaration is as follows:

template<    class Key,    class T,    class Hash = std::hash<Key>,    class KeyEqual = std::equal_to<Key>,    class Allocator = std::allocator< std::pair<const Key, T> >> class unordered_map;

I need to complete reverse search, that is, I used to find the value through the key, but now I used to find the key through the value. Std: unordered_map <vec3i, int> table; Because vec3i is its own class and does not have a default hash function, you must provide it yourself. Previously, I wrote the tuple-related comparison function.

class IndexCompare{public:    bool operator()(const vec3i& a, const vec3i& b) const    {        return a.i < b.i || a.j < b.j || a.k < b.k;    }};

The correct method is to use the "skip while equal, then compare" policy. Std: vector can be used directly to overload operator <operator.

class IndexCompare{public:    bool operator()(const vec3i& a, const vec3i& b) const    {        // Operator < and strict weak ordering        if(a.i != b.i) return a.i < b.i;        if(a.j != b.j) return a.j < b.j;        if(a.k != b.k) return a.k < b.k;        return false;    }};

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.