Include Order and Hidden Dependencies - c++

While looking for best pratices regarding include order, I was stumbling over this thread:
C/C++ include file order/best practices [closed]
#squelart was stating, that it is better pratice to include from local to global, as this reduces the chance of hidden dependencies. I just tested this in a VS2015 project with the following code:
StrTest.h
#pragma once
class CStrTest
{
public:
CStrTest();
~CStrTest();
std::string test;
};
StrTest.cpp
#include <string>
#include "StrTest.h"
CStrTest::CStrTest()
{
}
CStrTest::~CStrTest()
{
}
I couldn't reproduce the stated behaviour (hidden dependencie duo including string first in StrTest.cpp). The compiler gives me mulitple errors. So is this something out of the past or did I overlook something?
EDIT: VS2015 Compiler errors:
Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int
Error C2039 'string': is not a member of 'std'
Error C3646 'test': unknown override specifier

So is this something out of the past
No, the hidden dependencies are the standard behaviour and do happen in modern compilers. I don't know of VS, but GCC and Clang do compile your shown program without any errors. Demo: https://wandbox.org/permlink/ATJndwrOwirpDgDd
The compiler gives me mulitple errors.
Although an "implicit" include is poor style, it is still technically well formed as far as the standard is concerned as long as the implicitly included file is guaranteed to be included by you or whoever wrote the header that includes it - standard headers have no such guarantees.
Therefore I would be against such compiler feature that considers implicit includes as errors. An explicitly enable-able warning would be much more suitable.

I think the point of hidden dependence problem discussed there is that typically each file includes several other files and if header is not self-contained then including it may work in cases when it's implicit dependences are included by some other header and break everything when those other headers change and / or get moved / removed. In short: use of headers with hidden dependencies lead to extremely fragile code.
// foo.hpp
#pragma once
#include <string> // if we remove this unrelated `StrTest.h` header will be broken
...
.
// main.cpp
#include "foo.hpp" // if we move this one line lower `StrTest.h` header will be broken
#include "StrTest.h" // accidentally works fine
...

Related

‘numeric_limits’ is not a member of ‘std’

I am trying to compile an application from source, FlyWithLua, which includes the sol2 library.
I am following the instructions but when I run cmake --build ./build I get the following error:
In file included from /home/jon/src/FlyWithLua/src/FloatingWindows
/FLWIntegration.cpp:10:
/home/jon/src/FlyWithLua/src/third_party/sol2/./upstream/sol.hpp: In lambda function:
/home/jon/src/FlyWithLua/src/third_party/sol2/./upstream/sol.hpp:7194:59:
error: ‘numeric_limits’ is not a member of ‘std’
7194 | std::size_t space = (std::numeric_limits<std::size_t>::max)();
There are several other errors on the same line after this, but I guess they might just go away if I can solve this one.
there are several similar issues with the solution to add the following includes to the .hpp file
#include <stdexcept>
#include <limits>
the sol.hpp file includes the following imports:
#include <stddef.h>
#include <limits.h>
https://sol2.readthedocs.io/en/latest/errors.html gives some hints about the why the compiler might not recognize these includes:
Compiler Errors / Warnings
A myriad of compiler errors can occur when something goes wrong. Here
is some basic advice about working with these types:
If there are a myriad of errors relating to std::index_sequence, type traits,
and other std:: members, it is likely you have not turned on your C++14 switch for
your compiler. Visual Studio 2015 turns these on by default, but g++ and clang++
do not have them as defaults and you should pass the flag --std=c++1y or
--std=c++14, or similar for your compiler.
the src/CMakeList.txt file has the following line:
set(CMAKE_CXX_STANDARD 17)
I'm only faintly familiar with C/C++ and this all seems very complicated to me, but I'm hoping that there might be an easily recognizable cause and solution to this to someone more skilled.
cat /etc/*-release gives
DISTRIB_RELEASE=21.10
DISTRIB_CODENAME=impish
DISTRIB_DESCRIPTION="Ubuntu 21.10"
$ g++ --version
g++ (Ubuntu 11.2.0-7ubuntu2) 11.2.0
/home/jon/src/FlyWithLua/src/third_party/sol2/./upstream/sol.hpp:7194:59:
error: ‘numeric_limits’ is not a member of ‘std’
7194 | std::size_t space = (std::numeric_limits<std::size_t>::max)();
This error message implies that src/third_party/sol2/./upstream/sol.hpp header uses std::numeric_limits, but also that std::numeric_limits hasn't been defined. The simplest explanation for that is that the header that defines std::numeric_limits hasn't been included. In such case, the solution is to include the header that defines std::numeric_limits.
the sol.hpp file includes the following imports:
#include <stddef.h>
#include <limits.h>
This confirms the problem. Neither of those headers define std::numeric_limits.
https://sol2.readthedocs.io/en/latest/errors.html gives some hints about the why the compiler might not recognize these includes:
Those hints may apply to some other cases, but not this one. std::numeric_limits has been part of the C++ standard since the beginning, so language version has no effect on its existence.
Conclusion: According to the quoted error message, sol.hpp uses std::numeric_limits which is defined in the header <limits>, but according to you, it doesn't include that header. If this is the case, then this is a bug in the sol.hpp file. Correct solution would be to fix the sol.hpp file by including <limits> in that file before using std::numeric_limits.

Compile error that goes away with comment/debug/uncomment/debug on a single line

Below is a header file in my program.
I was getting a compile error, saying that I was missing a semi-colon before partyPack.
There is none missing. There were two other errors but I don't recall what they were.
What's really confusing to me is I commented out Pack partyPack; compiled (failed because it was referenced in the .cpp), and when I uncommented and tried again, it compiled and ran.
What could cause this behavior?
#ifndef PARTY_INTERFACE
#define PARTY_INTERFACE
#include "utility.h"
#include "Pack.h"
#include "Shop.h"
#include "Assets.h"
struct member
{...};
class Party
{
private:
const static int TEAMSIZE = 4;
member team[TEAMSIZE];
Pack partyPack;
const Inventory* itemList;
public:
Party(const Inventory* inputList);
void newTeam();
bool load();
bool save();
void findItem();
const void showParty();
const void showInventory();
void addToInventory();
~Party(void);
};
#endif
Update 1
I have been able to replicate the error ...
Below is a link to a github repo containing the program's files for reference, feel free to download and debug, etc. The last commit compiled for me in VC++ 2010. I've commented out the portions which require windows.h, it should compile universally ... I hope.
https://github.com/dsball/RPGShop/tree/master/RPGShop
Update 2
I've isolated the problem to being any time something is changed in one of the header files included in Party.h or in Party.h itself. The simple act of typing int a; and immediately deleting it(with nothing between those two steps) causes the bug. The errors follow:
Error 1 error C2146: syntax error : missing ';' before identifier 'partyPack' party.h 30
Error 2 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int party.h 30
Error 3 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int party.h 30
Then I comment line 30 in Pack.h //Pack partyPack, compile/start debugging (which fails), uncomment the same line and try again, it runs just fine.
Update 3
I have replaced Pack with Backpack after learning there is a Pack() pragma, but the issue remains the same.
As was mentioned by others, it does seem like there's something interfering with the definition of Party, but I can't find what it is.
(In later versions, pack has been renamed to backpack. This answer uses 'backpack' in place of 'pack')
When compiling under G++ (after appropriate modifications to remove Windows-specific code), I get this error:
$ g++ -std=c++0x *.cpp
In file included from Shop.h:6:0,
from Backpack.h:5,
from Backpack.cpp:1:
Party.h:30:2: error: ‘Backpack’ does not name a type
It looks like the issue is that Backpack.h is including party.h, but at line 5 in Backpack.h, the Backpack class has not yet been defined. Party.h includes Backpack.h in its line 5, but since Backpack.h has already been included, the #ifndef statement prevents Backpack.h from being included a second time (which would otherwise create an infinite loop of #include statements).
In summary, it looks like this issue is due to circular dependencies. I would find a way to break the dependency cycle between Backpack.h and Party.h.
In terms of why this is flaky, I'm guessing that VC caches fully-loaded headers as an optimization. If Backpack.h had been fully-loaded, then this error wouldn't occur.
Most likely Pack is undefined. But there's a header present that likely defines it, so...is it defined in another namespace? ( you might need to use explicit namespace locator like pack_namespace::Pack partyPack; )

Declaration of void abort() throws different exceptions

I am trying to write some C++ code (using the C++ API) for Festival and am getting stuck while trying to compile. Here is how I invoke g++:
g++ -Wall -pedantic -I../ -I../speech_tools/include/ helloFestival.C -o h -L../festival/src/lib/libFestival.a -L../speech_tools/lib/libestools.a -L../speech_tools/lib/libestbase.a -L../speech_tools/lib/libeststrings.a |& tee festival.runLog
The error I get is:
In file included from ../speech_tools/include/EST.h:48,
from ../festival/src/include/festival.h:47,
from helloFestival.C:4:
../speech_tools/include/EST_String.h:50: error: declaration of ‘void abort()’ throws different exceptions
/usr/include/stdlib.h:513: error: from previous declaration ‘void abort() throw ()’
The offending line in EST_String.h would be:
extern "C" void abort(void);
The main() function I have used can be found here: festvox.org/docs/manual-1.4.3/festival_28.html#SEC133
The compilation and linking instructions given here are the ones I have used.
I have looked this problem on the net and some of the solutions suggest that it maybe because of backward compatibility, or calling an abort() from within a destructor etc. My questions are:
How do I get rid of this?
Why do I see this error?
You see this error because the abort() function in speech_tools conflicts with the standard-mandated abort() function. There's probably no really good, clean way to fix this. If you have written EST_String.h yourself, name the function differently.
If not, don't include stdlib.h and EST_String.h in the same file. Yes, that's limiting and bad, but you are in a crappy situation here.
It is a very basic c error. The two definition for abort are conflicting I would try to remove the line in EST_String.h and maybe add a #include <stdlib.h> and see if it compiles after that.
I don't suppose including the stdlib header is the problem. However, you might get better mileage from including either <cstdlib> or <stdlib.h> as the very first header in your translation units
Rationale: just in case the definition in <cstdlib> adds the no-throw declspec.
So I really suggest to ... just fiddle with that. If it doesn't work either way (make sure you don't have conflicting includes or stale precompiled headers), I suggest just removing the offending declarion in EST_String.h
This is still a problem today. As a workaround, i'm using this piece of code.
It's ugly and hacky, but gets it working:
extern "C" void abort_est() { abort(); }
#define abort abort_est
#include <festival.h>
#undef abort

Strange error when adding #include <string>

I have the following very simple application that compiles and runs fine:
EDIT: changed the example to be simpilar to end confusion of the real issue
int main() {
return 0;
}
As soon as I add #include <string> (and not even reference std::string), it fails to compile and I get the following error:
/usr/include/c++/4.1.2/bits/allocator.h:82 error: expected template-name before '<' token
Along with about 456 other, similar errors.
Any ideas? Thanks!
UPDATE:
Line 82 of /usr/include/c++/4.1.2/bits/allocator.h references the template __glibcxx_base_allocator at the location of the error. That template is defined in bits/c++allocator.h. When I search the system for that file, I get 3 hits, but none of them are in /usr/include/c++/4.1.2/bits/ as one would expect.
I have version 3.1.6, 4.1.1, and 4.3.2, but not 4.1.2 as the rest of the includes I am using. I am not sure which one is being used (if any, however, I don't get any error for an unknown file), but it seems the problem may stem from this.
The problem appears to be the installed development packages are not correct or incomplete (not to be confused with corrupt). Forcing g++ to use different include versions corrects that:
g++ -nostdic++ hello.cc -o hello -I/usr/include/c++/3.4.6
All the alternative directories (4.1.1, 4.1.2 and 4.3.2) are incomplete causing inappropriate files to be included causing the unusually errors. For example:
/usr/include/c++/4.1.2/bits/allocator.h requires __glibcxx_base_allocator located in bits/c++allocator.h which is being included from either /usr/include/c++/4.1.1 or /usr/include/c++/4.3.2 and appear to be incompatible. Forcing the compiler to use the only complete set of includes rectifies this.
Almost certainly g++ is detecting .cc as a C source file, not C++ and passes it through to gcc instead of compiling as C++. You can easily test by renaming your file to hello.C. There's also a language parameter to g++ you can use.
EDIT: This seems to work fine in g++ 4.2 with a .cc extension so that might not be it. Do you have any other headers included you aren't showing us? They could be interfering with <string>.
EDIT2: Alternatively your headers might not be set up right. Does this work:
#include <string>
int main()
{
return 0;
}
Errors like this have been heard of to occur when the C++ standard library headers are corrupted/not fully installed – maybe there is even a message referring to a missing include among your 456 other errors.
In any case, make sure that libstdc++-devel, resp. the package containing the C++ standard library header files of your distribution, is properly installed.
Check your include path. The paths can be specified as environment variables or specified on the command line. You could be using an include file from a different compiler or different version of the same compiler.
Also, try using <cstdio> rather than <stdio.h>.
Another suggestion: change <> to "".
This could be error caused at preprocess stage. Just preprocess your cpp file by passing flag -E to gcc and Look at the place the compiler complains.

Is there an alternative to suppressing warnings for unreachable code in the xtree?

When using the std::map with types that use trivial, non-throwing, copy constructors, a compiler warning/error is thrown (warning level 4, release mode) for unreachable code in xtree. This is because the std::map has a try-catch in it that helps maintain the state of the tree in the case of an exception, but the compiler figures out that the catch statement will never be called if the stored elements don't throw. These warnings can be easily suppressed with the following lines at the top of the .cpp file:
#pragma warning(push)
#pragma warning(disable:4702)
#include <xtree>
#pragma warning(pop)
Is there a way to bypass this warning/error without changing the warning level, building in debug, suppressing the warning, or using a different type in the map? Is there plans to change this in the standard library?
Update:
Maybe it is compiler specific. I am using vc7.
The error is below:
c:\program files\microsoft visual studio .net 2003\vc7\include\xtree(1116) : error C2220: warning treated as error - no 'object' file generated
c:\program files\microsoft visual studio .net 2003\vc7\include\xtree(1116) : warning C4702: unreachable code
Apparently the xtree is used by the std::map.
Unfortunately it looks like xtree is part of the underlying implementation of map in VC7, and as such there isn't much that can be done to mitigate it. It looks like it's a bug in the standard library.
Is it a possibility to use a newer compiler? I'm fairly sure there are free downloads of more recent versions of the compiler you could use, and perhaps they've fixed this issue.
If that's not an option, probably the best solution is to wrap the include of map into your own private header, complete with a comment and the #pragma+include <xtree> lines you already discovered (in addition to an include of map. This way you hide the workaround from normal use.