I want to ban use of iostreams in a code base I have (for various reasons). Is there a way I can inspect symbol files or force the compiler to emit an error when that API is used?
5 Answers
A simple approach is provide a dummy iostream implementation that does nothing but throw a compile-time error.
The following example assumes a GCC toolchain - I imagine the process is similar with other compilers.
First, create your dummy iostream file:
#error 'Use of iostream is prohibited' Some dummy application code to demonstrate:
#include <iostream> int main (int argc, char** argv) { std::cout << "foo!"; return 0; } Compile as follows (assuming the dummy iostream and main.cpp are in the working directory):
g++ -I. main.cpp Compilation fails with the following errors:
In file included from main.cpp:2:0: ./iostream:1:2: error: #error 'Use of iostream is prohibited' main.cpp: In function 'int main(int, char**)': main.cpp:4:2: error: 'cout' is not a member of 'std' Added bonus: symbols usually declared in that file (e.g. cout here) are undefined, and so get flagged in the compiler output as well. As such, you also get pointers to exactly where you're using your prohibited API.
UPDATE: Instructions for Visual C++ 2012.
As @RaymondChen points out in the comments below, a solution tailored to Visual C++ is likely more useful to the OP. As such, the following outlines the process I went through to achieve the same as the above under Visual C++ 2012.
First, create a new console project, using the above C++ code. Also create the dummy iostream header I described above, and place it in a directory somewhere easy to find (I put mine in the main project source directory).
Now, in the Solution Explorer, right click on the project node and select "Properties" from the drop-down list. In the dialog that appears, select "VC++ Directories" from the tree on the left. Prepend the directory containing the dummy iostream file into the list of include directories that appears on the right, separated from the other directories with a semicolon:

Here, my project was called TestApp1, and I just prepended its main directory to the $(IncludePath) that was already there. Note that it is important to prepend rather than append - the order of the directories in the list determines the search order, so if $(IncludePath) appears before your custom directory, the system header will be used in preference to your dummy header - not what you want.
Click OK, and rebuild the project.
For me, doing so resulted in the following errors in the VC++ console (edited slightly for brevity):
error C1189: #error : 'Use of iostream is prohibited' IntelliSense: #error directive: 'Use of iostream is prohibited' IntelliSense: namespace "std" has no member "cout" Note that IntelliSense also picks up the (now) illegal use of cout - it is highlighted with an error mark in the editor.
9 Comments
std:: before cout. And seriously, please don't add a using.#include <iostream> doesn't even require that a file called iostream exist or even be used. The compiler could, in theory, sprinkle the magic sauce from a database, or the Internet, or via telepathy.This is a nasty hack, but it should work.
The C standard (and consequently the C++ standard as well) allows preprocessor tokens in #include directives. This is also known as "computed includes".
Thus, adding something like -Diostream to CFLAGS inside your makefile (or to compiler options in your IDE's project settings) should reliably break the build if someone tries to use iostream.
Of course, with an empty macro, the error message will not be very informative, but you could instead use something like -Diostream=DUDE_DONT_USE_IOSTREAM, which will show an error like: DUDE_DONT_USE_IOSTREAM: file not found.
It's also something that you can turn off again without much hassle if you change your mind later. Just remove the build option.
5 Comments
/D if it doesn't understand -D. Are you trying to find a more ridiculous downvote than the one above in the answer by @Mac or what's the issue with you today? :)-D not /D then you can just put #define iostream DUDE_DONT_USE_IOSTREAM on top of file if I understand the answer correctly.-D in the makefile (or in project settings) is much nicer, less intrusive (although it still uses the preprocessor) and more comfortable.Your idea to inspect symbol files is feasible and very realistic. virtual ~ios_base(); is a single method that all streams will inherit, and which can't easily be inlined since it's virtual and non-trivial. Its presence in an object file is therefore a very strong indication of IOstream use.
Comments
In addition to compiler-assist method mentioned by Mac you can use generic search functions. For example (I assume zsh shell - for bash doesn't have ** and on Windows you need to find how to do it with Powershell):
# Find all mentioning on `iostream` `cin` in all files ending in cc in all subdirectories of current directory grep iostream **/*.c grep cin **/*.cc If you don't want to/can't use command line you can use your favourite editor and search for unwanted symbols.
I usually combine both methods:
- Compilation, especially of large project with large number of templates, is slow while searching is fast so you're more productive with search
- On the other hand search operates is not exact and might miss something. So I'd use header tricks to verify solution done in previous step
- As final verification you can search for symbols after compilation. It is especially useful if you compile with no optimization. You can use
objdumpor similar (depending on platform) and watch for imported symbol (this works if you don't say link statically to something using iostreams).
1 Comment
No, not at all. For a very limited subset, you could provide your own definitions, causing the linker to error at the duplicates. This would be very undefined behaviour though. And a good portion is templates that aren't susceptible to this. Without doing drastic things like deleting the iostream header, or using a compiler like Clang and modifying the source code, there's really nothing you can do.
#errorpreprocessor directive to give friendly error message.iostreamsoristreamsandostreamsas well? Just thecinandcoutobjects (as well ascerrand the wide stream variants) or even instances from thestringstreamandfstreamvariants?<string>includes<iostream>? C++ has no restrictions on that, unlike C, and skishore's solution would break that.