Avoiding Duplication

Started by
8 comments, last by Zahlman 17 years, 1 month ago
I'm relatively new to C++ so I am looking for a somewhat simple response and explanation. Any tips or information is appreciated! I am working with a few different files that are all included together. However, in one file there is a piece of code that I don't want to get "called" more than once. I assume the standard method to fix this is to use:

#ifndef VAR
#define VAR
//Code
#endif

However, I remember reading that is a temporary way of doing this, and probably not something I would keep permanently. Is that the case? Is there a better (more efficient, more simple, etc.) way of doing this? Possibly I am confused about the whole situation in general? Thanks a lot.
James
Advertisement
#ifndef VAR#define VAR//Code#endif


These are called preprocessor directives and macros. The construct in your example is what we call conditional compilation. It's common usage is to make sure the compiler only compiles a piece of code once, even if it is included in several files. So what it basically says is: If the variable VAR has not been defined, then define VAR and compile this code, otherwise do nothing. Which means that for the first file getting compiled the header will be processed since VAR is not defined, but after that first compilation VAR will now be defined so all the other files will only link to the already compiled code instead of compiling it again.

Quote:
one file there is a piece of code that I don't want to get "called" more than once


I don't know if it's even possible to use preprocessor directives to restrict code from getting called more than once. They are processed during compilation, not in run-time.
Best regards, Omid
That won't affect whether or not the code is executed more than once. What it will do is prevent the compiler from processing the code more than once.

Can you post the code you want to restrict? The simplest solution is to have a bool variable someplace that is initialized to false, which you then set to true once the code has run. Then all you need to do is add a check to see if that variable is true; if it is, you skip the code (either using an if statement, or by returning out of a function, etc.).

The best place to locate the variable depends on the code you want to limit.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by Omid Ghavami
*** Source Snippet Removed ***

These are called preprocessor directives and macros. The construct in your example is what we call conditional compilation. It's common usage is to make sure the compiler only compiles a piece of code once, even if it is included in several files. So what it basically says is: If the variable VAR has not been defined, then define VAR and compile this code, otherwise do nothing. Which means that for the first file getting compiled the header will be processed since VAR is not defined, but after that first compilation VAR will now be defined so all the other files will only link to the already compiled code instead of compiling it again.


Thanks for the clarification.

If I have some sort of code (a class or a function for example) in one file and I need to use that particular definition in multiple other files, I would draw warnings and errors as the compiler hit it each time, correct? If thats the case, am I doing my including the wrong way (I.e. I'm including one two many times) or are there times where I wont be able to avoid it?

I'm sorry if this all seems sort of ambiguous. I don't really have code on the computer yet. I am just trying to plan around a project and so I am wondering if these preprocessor directives are considered "good practice", or I am just over including way too many times.

I believe "call" was improper terminology on my part. My apologies.

I did think of using a if to check a bool, but that seemed overly simplistic to me, but I could be wrong (it may be the only way to do it!)

Thanks again.
James
If you need to ensure that #including a header multiple times doesn't cause problems, then the #ifndef/#define/#endif solution will work fine. It's a very commonly used idiom in C++ and there's not really anything wrong with it; however, depending on how you lay out your header files, you may not need to use it very often. A common rule of thumb is "never #include anything in a header file", which will help avoid this issue; some people use this rule, others find it annoying. Just pick something that works well for you.

If your entire header file is inside the #ifndef (commonly referred to as an inclusion guard), you can also consider using #pragma once. That line will instruct the compiler to only load the header file one time, which has basically the same effect as inclusion guards. (Caveat: there is a subtle difference in some compilers, but I won't get into it because chances are you won't encounter the difference unless you're doing some weird voodoo with header files and multiple inclusions.)

The only problem with #pragma once is that it's not "official" C++ - it isn't guaranteed to work in all compilers. However, the GCC compiler family and Visual C++ both support it, and they're the dominant compilers for C++ on the PC; so if you only need to support one or both of those compilers, #pragma once will save you a little bit of typing over inclusion guards.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Gamedev's own Organizing Code Files in C++ is a good read on preventing compilation errors when dealing with modularizing your code. Now, this may not answer your initial question as it phrased, but based on your second post it may be what you want.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

Quote:Original post by JBS103

If I have some sort of code (a class or a function for example) in one file and I need to use that particular definition in multiple other files, I would draw warnings and errors as the compiler hit it each time, correct?


Not exactly. While you normally can't have multiple definitions of something in the program, you are allowed to define a class or inline function in multiple translation units (i.e. source files) as long as each definition only appears once in each translation unit and each particular definition is roughly identical in each file (which mainly means each definition consists of the same sequence of tokens, but there's a bit more than this - for the formal restrictions see section 3.2.5 in the standard). Note that you can have as many declarations of something in the program as you want, provided that the declarations are not also definitions.

What this means is that including the same header in multiple files should not necessarily give errors. However, if you include the same header more than once in the same file you probably will get errors. Sometimes it is hard to avoid multiple includes of this nature. Consider:

/* file1.h: */#include "file3.h"//declarations.../* file2.h: */#include "file3.h"//more declarations.../* impl.cpp: */#include file1.h#include file2.h //Uh-oh! file3.h included twice!//...


If this happens, you will probably get errors from multiple definitions. Include guards can fix this:

/* file3.h: */#ifndef FILE3__H#define FILE3__H//...#endif/* Now if file3.h is included more than once in a particular file, * it will only be processed once for that file, which will prevent multiple * definitions. */


You need declarations to be present in every source file that uses them, but you don't always need the actual definitions (except for things like classes and inline functions, which the standard lets you define more than once as I mentioned above). You can declare a function in a header file, and then define it in a source file, and as long as any code that calls that function includes the header file (so that the declaration can be seen), the compiler will not have any problems. The compiler doesn't need to see the actual definition yet; the linker will make sure that the right function is called.

Quote:I don't really have code on the computer yet. I am just trying to plan around a project and so I am wondering if these preprocessor directives are considered "good practice", or I am just over including way too many times.


Include guards are commonly used in C++ projects, and there really isn't anything wrong with them. Preprocessor directives are usually to be avoided, but in this case there's often no better alternative. Just make sure that the macro you define in the header has a fairly long and uncommon name, because that identifier could cause name clashes in the source file. For example:

/* read.h: */#ifndef Read#define Read //<---BAD//...#endif/* main.cpp */#include "read.h" //include read.h for file reading utilities//Declare function to read a fileint Read(std::string filename); //OOPS! "Read" was #defined in the header                                //The compiler will replace Read with blank space//...


This can usually be avoided by writing the macro identifiers in all caps, with names that aren't likely to be found in a source file (e.g. MYHEADERFILE_H).

I'm aware that this wasn't a "simple response and explanation", but I hope it helps.
Reckoner - Thanks for the post and sample code (that especially). Exactly the kind of information I was looking for. I appreciate it. It wasn't overly technical either, so don't worry about it; I just didn't want to get bamboozled with overly technical documents and so on of what I can and can't do. Obviously you didn't do that.

nobodynews - No big deal. Seems like something I should read anyway and I have no qualms with extra information. Thanks.

ApochPiQ - Thanks for sticking with the thread. I am in fact using VC++ and am not planning to do anything too insane so #pragma once seems like a valid option.


And on a simple off-note, are there any true advantages, disadvantages, things I should look out for, etc. when prototyping functions? Do they avoid confusion (both for the compiler and the person reading) or is it more of a stylistic choice?

Thanks again! Everyone has been helpful.
James
Quote:Original post by JBS103
And on a simple off-note, are there any true advantages, disadvantages, things I should look out for, etc. when prototyping functions? Do they avoid confusion (both for the compiler and the person reading) or is it more of a stylistic choice?

You should always prototype functions, even if given the ordering and usage of your functions you do not need it.
After all, later you may choose to use the same functions in another file.

The obvious exception to this is static and blank namespace functions, which cannot be used outside the file they are declared in. These are rare.

In terms of what prototypes should like, you should make your prototypes contain descriprive names for the paramitters. This is more important than using discriptive names in the function itself, but since that is also important, you might as well have the same names in the function and the prototype.
Quote:Original post by King Mir
Quote:Original post by JBS103
And on a simple off-note, are there any true advantages, disadvantages, things I should look out for, etc. when prototyping functions? Do they avoid confusion (both for the compiler and the person reading) or is it more of a stylistic choice?

You should always prototype functions, even if given the ordering and usage of your functions you do not need it.
After all, later you may choose to use the same functions in another file.


Um, wow. Completely disagree.

Order your functions within the .cpp file to avoid prototypes as much as possible. (If you need a prototype, that indicates that some set of functions can call each other in a cycle, and that's a sign that you might not be doing what you want, because recursion is usually limited to a single function "cycle".)

If you later find that the function will be useful in another file, then you add the prototype to the *header* for the current file (creating it if it doesn't exist).

This way, you avoid redundancy (and with it, extra maintenance work), highlight those circular dependencies and reinforce in your mind the distinction between header and implementation files.

This topic is closed to new replies.

Advertisement