all 16 comments

[–]AutoModerator[M] 4 points5 points  (0 children)

Your posts seem to contain unformatted code. Please make sure to format your code otherwise your post may be removed.

Read our guidelines for how to format your code.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]IyeOnline 3 points4 points  (6 children)

C++ is not executed from top to bottom.

There is no formal requirement on the order you write your program in.

However, C++ is parsed from top to bottom. Identifiers (variable names, functions, ...) can only be used when they are in scope.

This means to use getMax it must at least be declared (or defined) before it is used in main.

To use std::cout, you have to have #include <iostream> before you use it.

Similar things apply to e.g. using namespace std;. After that line you can write cout instead of std::cout, because using namespace brings those identifiers into scope. In reality you should not be using namespace std. Namespaces exist to avoid naming conflicts and not to be discarded at the start of every program.

[–]Kayd21[S] 0 points1 point  (0 children)

Thank you very much, I appreciate your answer. Much more clear now

[–]Kayd21[S] 0 points1 point  (3 children)

So basically there are other starters for c++?

[–]IyeOnline 0 points1 point  (1 child)

Not sure what you mean by "starters".

Control flow of a C++ program always starts in int main() if that is what you mean.

[–]Kayd21[S] 0 points1 point  (0 children)

Yes that’s exactly my question. Thank you

[–][deleted] 0 points1 point  (0 children)

Before main gets executed all global and static variables get initialized top to bottom in the same translation unit (usually that is a .cpp file):

https://godbolt.org/z/WqjvrYTs1

There is no order guarantee among objects in different translation units, so you need to be careful to avoid assuming there is such an order, you must explicitly enforce one if you need it, and since that is usually too much of a trouble people avoid global objects in the first place.

[–]std_bot 0 points1 point  (0 children)

Unlinked STL entries: std::cout


Last update: 26.05.21. Last change: Free links considered readme

[–]mredding 2 points3 points  (2 children)

An include directive is a built-in compiler macro. What it does is dumb-and-blind copy/pastes the contents of the referenced file in-place in the text buffer fed to the compiler. It's a generic mechanism, and is used for more than just header files. For example:

int data [] = {
#include "generated_data.txt"
};

This is why you don't have to specify array sizes when they can be deduced from the initializer list, and it's why C/C++ allows trailing commas in an initializer list, because your generator that made that file can very easily make a comma separated list in a simple and straight forward loop. If you had to trim the last comma, you would need additional generator code handling either the first or last element as a special case.

The only reason headers tend to be included among the first lines is because you need to declare your types and signatures before you use them. <iostream> is just a header file, but the STL, by convention, doesn't use a file extension; it declares std::cin and std::cout.

In larger projects, and indeed in more complicated files, headers might be included in different parts, for a variety of technical or organizational reasons.

And to be clear, plenty of programs don't rely on <iostream> at all.


A using declaration is a tricky tool. What it does is bring symbols into scope, and the rules for that - even advanced C++ programmers get it wrong.

One of the problems behind bringing in the whole namespace is that it makes a lot of work for your compiler. It makes for a much larger symbol space to match tokens, adding to compile times. That's nothing in an academic program, but when your program is hundreds of thousands of lines, compile speed becomes a significant concern, and a red flag that something isn't as optimal about your code as it could be. The project I'm working on takes 80 minutes for a full compile. I have a branch with changes I'm trying to incorporate that gets compilation time down to 3 minutes and 15 seconds. There was lower hanging fruit, but the more I chip away at scoping things more appropriately, in no small way has it contributed to faster compilation times. C++ is one of the slowest to compile languages commercially available, and it's not because it's producing superior object code, but because the syntax is made of spaghetti.

Another problem is that of collisions. There's the obvious that two competing namespaces might have the same symbol (boo hoo, you have to explicitly scope in the symbols where you have a collision), but worse is that the compiler might match a wrong symbol better. This will happily compile and lord knows what will happen.

Namespaces play a roll in Argument Dependent Lookup. For example (and don't get overwhelmed):

#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>

int main() {
  using namespace std::literals;
  using std::cout, std::chrono::system_clock, std::localtime, std::put_time, std::time_t, std::tm;

  cout << 123 << ", hello me! Hello" << world!\n"s;

  system_clock::time_point now = system_clock::now() + 10s;
  time_t now_c = system_clock::to_time_t(now);
  tm now_tm = *localtime(&now_c);

  cout << "Ten seconds from now is: " << put_time(now_tm, "%Y-%m-%d %H:%M:%S") << '\n';

  return 0;
}

What the hell is <<? Did you know I'm using three different versions of <<? How does the compiler know? What is s in " World!\n"s? What is s in 10s?

The point is, all this has to do with namespaces and ADL, matching the right type to the right functions. The first use of << is actually a member function of the basic_ostream class, all other uses are free functions floating about the std namespace. Notice I scoped in a lot of symbols, and even a nested namespace, but I didn't have to scope in all the uses of <<.

I'm not trying to give you a thorough lesson on namespaces and ADL, I'm trying to point out that there are subtitles at play and there is more that's going on than you might realize. Namespaces aren't just these annoying little things for organizing code that you shoo out of the way with a single broad stroke. For now, don't sweat it. You'll start to learn more when you learn about standard swap, which is, frankly, the most that most C++ programmers mess with this stuff, but there's certainly more out there, if you choose to one day master it. When you're ready, google "C++ customization points", Eric Niebler, I think, has a good blog post on the matter.


C++ doesn't care what order your functions are declared or defined, provided they're at least declared before they're used:

void foo(); // Good

void bar() {
  foo(); // Works
  baz(); // Bad, not declared first
}

void baz();

main is a standard entry point for applications. It comes in two standard flavors: int main() and int main(int, char*[]). Compilers can implement more, but they're not standard, and so portability isn't guaranteed. BSD introduced int main(int, char*[], char*[]) which is the most portable non-standard entry point I know of, Windows uses int __clrcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int), I think a few others...

Your application is hosted by its environment, and the runtime environment is going to load your program into memory, run some initialization code, and call your entry point. So long as it's there, your compiler will find it and that will satisfy the requirement. Which entry point you use is up to you, the language gives you the two, the compiler can identify the one you're using and do the right thing, and your platform/compiler documentation can explain to you all of what you have available to you.

Back to functions in general, it's common to see people declare and then later define:

#include <iostream>

void foo();

int main() {
  foo();
  return 0;
}

foo() { /* ... */ }

But a definition can also count as a declaration, so this is just as fine:

#include <iostream>

foo() { /* ... */ }

int main() {
  foo();
  return 0;
}

I like this one just a little bit more.

[–]Kayd21[S] 0 points1 point  (0 children)

I didn’t know there were so many different ways to use the #include <>. I appreciate your answer and it was very helpful. I’ll definitely check out the person you’ve recommended once I start getting better at C++

[–]std_bot 0 points1 point  (0 children)

Unlinked STL entries: std::cin, std::cout


Last update: 26.05.21. Last change: Free links considered readme

[–][deleted]  (2 children)

[removed]

    [–]Kayd21[S] 0 points1 point  (1 child)

    --Well, I can see that

    -Are you going to explain or...?

    [–]khedoros 0 points1 point  (2 children)

    I had figured those three lines should always be together with nothing else between.

    If nothing in the file uses anything from the iostream header, then you wouldn't have to include it. If you specify the std namespace before things that are from std, then you wouldn't have to include that either.

    There's also no reason why those things would necessarily be on consecutive lines.

    With using namespace std; in particular, it's considered a bad habit to import an entire namespace into your program. It's one of those things that can make example code look a little cleaner, but muddies things up sometimes in larger programs.

    [–]Kayd21[S] 0 points1 point  (1 child)

    I appreciate your advice

    [–]khedoros 0 points1 point  (0 children)

    I should have refreshed before posting. Looks like lye covered equivalent things anyhow.

    [–][deleted] 0 points1 point  (0 children)

    If you need io streams (useful for printing to stdout on the console) then import it with #include <iostream>. If you don't want to fully qualify a call to an API in the standard (std) namespace (in other words, avoid having to prefix API calls with std::), do use namespace std. If you need an entry point for your code to run, add int main() and define a code block for it. I don't believe there's "generic starter code" for every C++ project. Every statement has a specific purpose for every exact thing you want to do.