Why does map not include out_of_range? - c++

Consider the following code that doesn't compile:
#include <map>
//#include <stdexcept> // uncommenting this works
int main() {
std::map<int, int> test;
try {
test.at(10);
} catch(std::out_of_range& e) {
}
return 0;
}
Why does std::map not include std::out_of_range, even if it uses it? (The .at() can throw a std::out_of_range).
When I also include <stdexcept> it compiles, and works fine.

Whether a standard header does include another header is an implementation detail unless explicitly specified.
With templates its a little more involved, but just to point you in some direction, consider this toy example:
// header: my_map.h
struct my_map {
int at(int);
};
Only in the source file the header for the exception has to be included:
// source: my_map.cpp
#include <stdexcept>
int my_map::at(int) {
throw std::out_of_range("bla");
}
std::map surely looks different but it may hide the exception from the header as well.
Is it also ok for a header to not include a decl for std::pair
The headers that are specified to be included via <map> are <compare> (since C++20) and <initializer_list> (since C++11). Nothing more.
<map> may include other headers and thats one of the "implementation details" mentioned in comments. The part of the standard that explicitly allows standard headers to include others is [todo.put reference here].
The simple rule of thumb that avoids such headace is: Include what you use.
but throwing std::out_of_range is not an "implementation detail" - it is part of the specification of std::map!
Consider that this code compiles with gcc 10.2:
#include <map>
int main() {
std::map<int, int> test;
try {
test.at(10);
} catch(...) {
return 1;
}
return 0;
}
The out_of_range exception is thrown and catched, and 1 is returned. We know what at may throw and catch(...) will catch it, yet no include is needed for the exception.
On the other hand, the same compiler rejects your example, but compiles it when we add a seemingly unrelated header:
#include <map>
#include <sstream> // why this?
int main() {
std::map<int, int> test;
try {
test.at(10);
} catch(std::out_of_range& e) {
}
return 0;
}
However, this only works by coincidence. Apparently <sstream> does include <stdexcept> somewhere along the line. But this may change with compiler version or between differernt compilers.

The implementation of std::map doesn't have to be all in the header file. Yes this is a class template, but it is free to use any internal non-template components.
Consequently, the header file doesn't have to mention std::out_of_range (it may well be hidden inside one of those non-template components) and so doesn't have to have its definition visible anywhere, or behave as if it includes <stdexcept>. It is explicitly allowed to, but there is no implicit or explicit obligation in the standard for it to do so. So it might, or might not.
In fact g++-9 behaves as if <map> includes <stdexcept>, and g++-10 does not, and in both cases they are correct.

Why does std::map not include std::out_of_range
Assuming you are using GCC 10, GCC developers decided to optimize header dependencies in C++ Standard Library code. From Porting to GCC 10:
Header dependency changes
Some C++ Standard Library headers have been changed to no longer
include the <stdexcept> header. As such, C++ programs that used
components defined in <stdexcept> or <string> without explicitly
including the right headers will no longer compile.
Previously components such as std::runtime_error, std::string and
std::allocator were implicitly defined after including unrelated
headers such as <array> and <optional>. Correct code should include
the appropriate headers for the classes being used.
Also from GCC 10 Release Notes:
Reduced header dependencies, leading to faster compilation for some
code.

Related

Why does my program compile successfully if I don't include <string.h>?

I've been puzzled by this for a while. To test this out, I made a simple program that just creates a std::string variable and prints it out to the screen. However, it doesn't include <string.h>.
#include <iostream>
using namespace std;
int main()
{
string name = "Test";
cout << name << endl;
return 0;
}
What confuses me is that this program compiles and runs perfectly. Right now I'm using the clang compiler that came with the XCode Developer Tools. Is this intended behavior? I hope this question isn't too ridiculous since I just started learning C++.
The reason you do not need to include the #include <string.h> header file is because when you include the #include <iostream> header file it includes std::string.
However, do not rely on it. What may work on your compiler may not work on another. Always include the proper header files.
To edit your example this is how you should use it:
#include <iostream>
#include <string>
int main()
{
std::string name = "Test";
std::cout << name << std::endl;
return 0;
}
Also note: why you should not use using namespace std;.
Why does my program compile successfully if I don't include <string.h>?
Because you don't use any definition / declaration from <string.h>.
program compiles and runs perfectly ... Is this intended behavior?
It is incidental behaviour.
There are no guarantees that one standard header wouldn't include other standard headers. It just so happens that <iostream> included <string> in this particular version of the standard library. Since there is no guarantee for this, it would be a mistake to rely on such transitive inclusion.

Is <initializer_list> included in <iostream>?

I know that the below code-block compiles
#include<initializer_list>
int main()
{
std::initializer_list<int> li = {1,2,3,4};
}
I can't understand why this also compiles
#include<iostream>
int main()
{
std::initializer_list<int> li = {1,2,3,4};
}
Is <initializer_list> included in <iostream>? According to this, it doesn't seem to be. Could this be a machine/compiler dependent thing?
Is <initializer_list> included in <iostream>?
It is not specified nor guaranteed to be.
But also, it is not guaranteed to not be included. Any standard header may include any other standard header, or system header. You should not rely on such transitive inclusion because another (version of the) standard library might not have such inclusion. Same generally applies to all third party headers as well. Only rely on a transitive inclusion if it is documented and guaranteed.

When I split up my C++ class into a header and implementation I get 20 compiler errors which don't make sense

I was splitting up my program into a header and implementation file per usual, however, when I tried to run the code, I got a ton of compile errors. This seems to be an issue with my computer or IDE, but I have not seen it before. This should be relatively simple as it is for a class project.
The code is as follows:
colorPicker.h
#pragma once
class colorPicker {
private:
string colorArray[7];
public:
colorPicker();
void printAllColors();
string randomColor();
};
colorPicker.cpp
#include "colorPicker.h"
#include "stdafx.h"
#include <iostream>
#include <string>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
colorPicker::colorPicker() {
colorArray[0] = "Red";
colorArray[1] = "Green";
colorArray[2] = "Purple";
colorArray[3] = "Yellow";
colorArray[4] = "Orange";
colorArray[5] = "Indigo";
colorArray[6] = "Pink";
}
void colorPicker::printAllColors() {
for (int i = 0; i < 7; i++) {
cout << colorArray[i] << endl;
}
}
string colorPicker::randomColor() {
srand((unsigned)time(0));
int j = 0;
j = rand() % 7;
return colorArray[j];
}
main.cpp
#include "colorPicker.h"
#include "stdafx.h"
#include <iostream>
#include <string>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main() {
colorPicker p;
p.printAllColors();
cout << "Random Color: " << p.randomColor() << endl;
system("pause");
return 0;
}
There are 20 errors given by the compiler, however, they all seem to be stemming from two undeclared identifiers which are most definitely declared. I am at a loss for what I could possibly do to fix it, and this project is due Sunday. Thank you.
Here are the errors
Tons of Errors
You need #include "colorPicker.h" in colorPicker.cpp. Each .cpp file is handled basically independently by the compiler and they are all joined at the end by the "linker." When the compiler looks at colorPicker.cpp without an include of the corresponding header, it's at a loss as to the definition of all the classes you're working with.
There are a few things you are doing wrong. I'll just pick on a couple.
Firstly, each header file you write should be self-contained - in the sense that, if it relies on content of some other headers, it includes that header. If a compilation unit (a formal name for a source file with a .cpp in your case) includes your header, it should not have to include something else your header depends on.
Second, it is a bad idea for a header to rely on any using directive, such as using namespace std. There are plenty of explanations of that available, so I won't repeat.
To understand the above, look at colorPicker.h
class colorPicker {
private:
string colorArray[7];
public:
colorPicker();
void printAllColors();
string randomColor();
};
Firstly, this depends on string, but there is no definition of string visible in the header file. Usage of that type depends on the standard header <string>.
Second, that string type is within namespace std. So your header relies on the compilation unit (the source file that includes your header) having previously used a using directive i.e. using namespace std.
To fix these two problems, change the header to
#ifndef SOME_MACRO_UNIQUE_TO_YOUR_COLOR_PICKER_HEADER
#define SOME_MACRO_UNIQUE_TO_YOUR_COLOR_PICKER_HEADER
#include <string>
class colorPicker
{
private:
std::string colorArray[7];
public:
colorPicker();
void printAllColors();
std::string randomColor();
};
#endif
(I've also done some minor changes of layout, since I have various reasons to prefer that.
However, the #include <string> means that this version will not fail to compile, as yours does, if it is included by a compilation unit that does not have #include <string>.
The usage of the fully qualified name std::string, rather than string, also means there is no dependence on the using directive using namespace std. It also means compilation errors can't be triggered in your header if your compilation unit has another using directive.
I've also used an include guard, rather than #pragma once. Although most modern compilers support #pragma once, it is actually not standard C++ (a #pragma, by definition in the standard, is a compiler-specific hook). Include guards are supported in standard C++.
If you've done that, your code should mostly compile as is. However, optionally, you may wish to
remove the using directives using namespace std from your other files. If you do that, you will need to change the definition of colorPicker::randomColor() in colorPicker.cpp so it returns the fully qualified type std::string rather than string.
Remove #include <string> from files that have #include "colorPicker.h". This is possible, since colorPicker.h now includes <string>. This step is optional, since there is no problem with including standard headers more than once in a compilation unit.
A few other notes
In C++, although it is not a major concern, it is usually considered better to use include <cstdio> and <cstdlib> rather than the C headers <stdio.h> and <stdlib.h>.
Your code is calling srand((unsigned)time(0)) whenever colorPicker::randomColor() is called. It is better to only call it once in an entire program, not in a function that may be called multiple times.
A header file should be self-contained as far as #includes go. That means that you should be able to #include the header file without having to include other stuff before it!
Your colorPicker.h does not meet that requirement. It apparently uses std::string from the standard library but does not have an #include <string> on top, so everyone who uses colorPicker.h has to remember to put an #include <string> before it. That's pretty annoying.
Even worse, colorPicker.h refers to std::string as string, which implies a using std::string; or using namespace std; somewhere before any #include "colorPicker.h" line, and both of those are very bad coding style in C++, if not used in tighter scopes.
Here's how to fix the header file:
#pragma once
#include <string>
class colorPicker {
private:
std::string colorArray[7];
public:
colorPicker();
void printAllColors();
std::string randomColor();
};
As far as your *.cpp files go, I can see that you are using #include "stdafx.h". Why? It's a non-standard Microsoft thing completely unnecessary in your case. You are also using it incorrectly. It must be the first include. Just remove it entirely.
Some other suggested cleanup:
using namespace std; lines in *.cpp files is not as bad as in header files, but if I were you, I'd just get rid of it completely. Just use complete names. Say std::cout, not cout. And so on. It's just the most consistent way and it avoids a lot of trouble.
You include a lot of headers which you don't need. For example, what's <ctime> for?
Don't use system("pause");. Do not look for artificial ways of pausing a command-line program.
You may need add head file and in colorPicker.h.
And the std namespace is needed while using string.
BTW, the header guards is recommended strongly.
#ifndef COLOR_PICKER_H
#define COLOR_PICKER_H
#pragma once
#include <string>
class colorPicker {
private:
std::string colorArray[7];
public:
colorPicker();
void printAllColors();
std::string randomColor();
};
#endif

C++ --- Shouldn't these mathematical functions/constants be undefined?

I would not expect the following code that prints the value of sin(pi/2) to work, without the inclusion of an additional header:
#include <iostream>
int main()
{
std::cout << sin(0.5*M_PI) << std::endl;
return 0;
}
and, as expected, upon compilation I get an error reading ‘sin’ was not declared in this scope and a similar error for the use of M_PI.
However, I am confused by the fact that if I include seemingly any boost library header, take just for example the lexical_cast.hpp, and instead run
#include <iostream>
#include <boost/lexical_cast.hpp>
int main()
{
std::cout << sin(0.5*M_PI) << std::endl;
return 0;
}
then the code works and it prints 1.
Why should including this boost header, which contains no definition of M_PI or sin(), allow this constant and function to be defined? Shouldn't I need to include a header, like math.h that includes these things for this to work?
Yes, it should work that way.
The boost headers you tried all have implicit dependencies (pow(), modf(), fmod(), log() etc).
This is a common thing in the C++ compilation model. Nothing to be alarmed by.
Guideline: always explicitly include the headers you directly depend on. And only those.
This prevents portability issues on platforms where the library header dependency tree differs e.g. <algorithms> and <numeric> aren't implicitly included with some other standard library headers (e.g. MSVC)

math.h macro collisions

Macro DOMAIN in math.h collides with enums and possibly other types. I don't know what to make of it.
#include <algorithm>
enum Type { DOMAIN };
int main(){
Type t = Type::DOMAIN;
return 0;
}
Compile with flag -std=c++11. The C99 version of this code compiles perfectly fine though:
#include <algorithm>
enum Type { DOMAIN };
int main(){
Type t = DOMAIN;
return 0;
}
I checked the source code and the library is to blame. algorithm includes stl_algo.h, in which there is ifdef:
#if __cplusplus >= 201103L
#include <random> // for std::uniform_int_distribution
#include <functional> // for std::bind
#endif
The following code compiles fine on c++11 compiler:
#include <random>
#include <iostream>
int main(){
std::cout << DOMAIN << std::endl;
return 0;
}
Is it a feature or a bug?
EDIT* dirty fix:
#ifdef DOMAIN
#undef DOMAIN
#endif
It's a bug (or a "wart" if you want to be generous).
All the rest of this answer refers only to GCC and the Gnu standard C library headers. The man page references are to a linux system (but I've added links to man7.org).
The DOMAIN macro comes from math.h's System V support. (See man matherr.) System V support is normally enabled by defining the _SVID_SOURCE feature-test macro (see man feature_test_macros), but it is enabled along with a raft of other extensions if _GNU_SOURCE is defined, or by default if no feature test macros are defined.
gcc predefines _GNU_SOURCE for C programs if the --std option is omitted or set to gnu##. The various --std=c## options cause __STRICT_ANSI__ to be defined. Consequently, compiling C code with some explicit C standard will suppress the System V extensions. That needs to be done because the System V extensions are not standards-compatible, not even with Posix, because they pollute the global namespace. (DOMAIN is just one example of this pollution.)
However, g++ defines _GNU_SOURCE even if --std=c++## is specified, and consequently the System V extensions will sneak in. (Thanks to #dyp for the link to this libstdc++ FAQ entry. and this long and inconclusive discussion from 2001 on the GCC mailing list)
An ugly workaround is to set up the features yourself, and then undefine __USE_SVID:
#include <features.h>
#undef __USE_SVID
#include <random>
#include <iostream>
int main(){
std::cout << DOMAIN << std::endl;
return 0;
}
(Live on coliru)
IMHO, this should not be necessary. But there it is.
§ 17.6.5.2 [res.on.headers] / 1 of N4140 says:
A C++ header may include other C++ headers. A C++ header shall provide the declarations and definitions that appear in its synopsis. A C++ header shown in its synopsis as including other C++ headers shall provide
the declarations and definitions that appear in the synopses of those other headers.
Therefore, it is valid for <algorithm> to #include <cmath> which injects the offending macro constant into your namespace.
Note, however, that your “quick and dirty fix” is disallowed by the standard (§ 17.6.4.3.1 [macro.names] / 1):
A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
You'll have to choose a name different from DOMAIN for your enum constant.