Pregunta

For some kinds of programs I need to use a constant high value to indicate some properties of some variables. I mean let color[i] = 1000000; if the i node in a tree is unexplored. But I quite often miswrite the number of 0s at the end, so I just wondered whether is it better to do it this way:

#define UNEXPLORED 1000000;
color[i] = UNEXPLORED;

I remember that somewhere I have read that it's much better to avoid using #define. Is it right? How would you tackle this problem?

¿Fue útil?

Solución

For simple constants, you can use either const or the new constexpr:

constexpr unsigned int UNEXPLORED = 1000000;

In a case like this, it's no difference between using const and constexpr. However, "variables" marked constexpr are evaluated at compile-time and not at run-time, and may be used in places that otherwise only accepts literals.

Otros consejos

For example use constants.

const unsigned int UNEXPLORED = 1000000;

or enums

enum { UNEXPLORED = 1000000 };

In the use of constants the two answers above are correct, however #define is not limited to that use alone. Another example of the use of #define is macros.

Macros

Macros are preprocessor-utilised pieces of code, and they work exactly like other #define declarations in that regard. The preprocessor will literally swap out the occurrence of your defined symbol with the code of the macro. An example:

#define HELLO_MAC do{ std::cout << "Hello World" << std::endl; }while(false)

int main(int argc, char** argv)
{
     HELLO_MAC;
}

That will literally swap out the HELLO_MAC symbol with the code I declared. If it were a constant it would do the exact same thing. So you can think of #defines for constants as a particular kind of macro.

With macros you can also pass parameters, and it is especially useful I find for enforcing logging/exception policies over code. For example

#define THROW_EXCEPT( ex_type, ex_msg ) /
    do{ throw ex_type( buildExString( (ex_msg), __LINE__, __FILE__ ) ); }while(false)

... 
// somewhere else
THROW_EXCEPT( std::runtime_error, "Unsupported operation in current state" );

That code allows me to ensure that everyone logs with the line of the file that threw the exception.

Templates are often a better choice instead of macros, but I cannot use template functions for this example because I need to use the __LINE__ and __FILE__ functions from the place of the throw, not from the location of the template function.

Where should you not use macros? Anywhere you can use something else. Macros, like any #define are preprocessed, so the compiler does not see them at all. This means that there is never any symbols created for HELLO_MAC or THROW_EXCEPT, and so they cannot be seen in a debugger. They can also be confusing if you get compile errors, especially if they are long macros.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top