Ok when i saw that code i thought hmm pretty clear it should be the int constructor since the object doesn'exist yet....then i saw your explanation and i shrug...really? then i tried it just to be sure....first instinct was right your "spoiler" is wrong

Did you miss the comment about copy elision? The compiler is allowed to optimize away the temporary, even if there are side effects. It doesn't have to, but it may (and most probably will). Some compilers may, and some may not. Some may with certain optimization settings, some may not. But it's important to remember that you may be constructing two MyStructs (the temporary, and the one you want) because, depending on what MyStruct is and what its constructor/destructor does, there may be side effects. It's another one of these "Betcha didn't see that coming, now did ya?!" that C++ can throw at you, because you test it a thousand times on a compiler/platform, and it works a specific way, and then you test the same code on another compiler/platform and it does something a little different.

If you don't believe me that both the int constructor and copy constructor are used in that code, try this:

It's a big WTF if you ask me. The copy constructor is required for it to compile (because it's technically required to do MyClass s(MyClass(5))), but it's never even called in the final code! Classic example of copy elision.

@Grafalgar: My posts show one example of exactly what you're looking for. Beginners are taught early on about constructors, but this little detail can potentially be a big pain in the butt that they don't learn until years later.

The problem is that no first-year CS course will cover all the things you have to know to use C++ proficiently. It's like asking "what's so hard about being a chef? Limit your answers to the subject of boiling water."

Well, yeah, boiling water isn't hard. There's a lot more to being a chef than boiling water.

OK, that's fair, but the point is that the stuff I deal with regularly with regards to C++ I, personally, do not find very hard nor complex. Instead of 1st year students, let's expand to what one might learn throughout your 4-year degree. Or maybe in your first year being a software engineer. A lot of things that are considered "too complex" I very rarely encounter, and that's clear across 14 years of dedicated C++ development. Moreover, what I'm particularly interested in is what makes C++ more complex than Java (or C#), at the beginner/novice level, without going into language obscurities that most people may not deal with.

I've never heard any complaints about semicolons. The fact that you should put one after a struct or class block but not after a namespace block is kind of weird, though.

Multiple inheritance is avoidable (and should be avoided).

I would add making sure code is portable to your list. There are quite a few complexities to handle there (type sizes, byte order, alignment, padding, standard headers that may or may not include other standard headers...).

My pet peeve: that whole header file / code file separation. Why does C(++) want me to juggle those two when every other language I've ever been exposed to conveniently uses one file for both? That's why I decided to make C# my primary language. I just try to design my projects around the supposed ~5% loss of overall speed.

Well, to be fair, exception safety can be a pain in any language. It's true that in C# you don't have to worry about leaking managed resources due to an exception, but it's still easy to stick your program in an inconsistent state especially if you don't follow DRY.

My problem with C++ as a language for beginners is that beginners normally learn by experimentation. They may read a book or take a class but at the end it's them with a compiler trying things out. The first consequence is that in this beginning stage it's very easy for them to think they've learned something about C++ that's actually incorrect. It's not like as beginners they have the experience to generate full coverage tests for their mini-experiments. Even if they do discover something correct about their own compiler they often mistake implementation specific behavior for behavior of the language as a whole. Heck, I've seen teachers do the same thing (evaluation order springs to mind).

The second consequence is that languages with clean grammars and good errors make for much better beginning languages because they can get logical immediate feedback. The semi-colon placement issue is usually a problem because the errors generated frequently point at the "wrong" line of code. Related to this is times when C++ will compile code into something very different than what was intended. The most vexing parse is one of these, but then you've got temporaries created when people wanted to actually wanted to call the base constructor in a derived constructor body, and similar.

Finally, C++ as a first language seems to discourage developing problem solving skills. Beginners learn that when they get stuck against a brick wall, it's probably the language they're fighting and rush off to get help with the latest syntax error or undefined behavior problem. And for people who learned a different language first, that's probably true 99% of the time; however, for someone who's trying to learn C++ at the same time as learning the basics of programming that may not be true in the majority of cases, but true often enough that running off to get help is positively reinforced.

There are people who have successfully learned to program with C++ as their first language. However, it seems like people who start with a different language and then learn C++ later generally get to the level of a proficient C++ programmer faster, and I've seen plenty of both.

My pet peeve: that whole header file / code file separation. Why does C(++) want me to juggle those two when every other language I've ever been exposed to conveniently uses one file for both?

It's basically inherited from C, which was developed in a time when computers were sufficiently low on memory that they literally couldn't fit all the symbols necessary for a complex program in memory all at the same time and still have room for actual code. Programmers would be able to identify which symbols were really needed and include only those headers.

It's basically inherited from C, which was developed in a time when computers were sufficiently low on memory that they literally couldn't fit all the symbols necessary for a complex program in memory all at the same time and still have room for actual code. Programmers would be able to identify which symbols were really needed and include only those headers.

Thank you, though I should have been more clear in indicating that I do understand the reason, but simply cannot stand the additional handling complexity. Of course it has its raison d'etre even today (embedded systems come to mind), but I might see the language in a more positive light if the .h/.c(pp) separation wasn't all but mandatory when targeting systems with plenty of resources. My apologies.

Actually, decided to take a look to it, and I think the answer for 1.1 (and thereby 1.2 potentially) may be wrong. That thing is pure pointer arithmetic which should be well defined really (it would make it point one byte after the array if overflow doesn't happen, whatever that address turns out to be - doesn't need to be memory). There's the problem of overflow though, which depending on how pointers are stored behaves differently (no idea what the standard says about how pointers can be stored).

If pointers are unsigned integers, then it'll just roll over back to the beginning in case of overflow.

If pointers are signed integers, then it's undefined behavior (though on two's complement systems it works the same way as for unsigned integers technically)

If pointers are something else (which was the case for really old systems), then... who knows what could happen, this is even worse than your usual undefined behavior.

And even in either case it's still wrong: if the allocated block of memory happens to be exactly aligned to the top of the address space, that would mean p + 10 is overflowed, and thereby we can't rely on the value of that address (in particular, it won't be after p + 9 at the very least, and most likely would end up before it). So the actual defined range in that sense would be p to p + 9, not p to p + 10.

Needless to say, answers 1.2 and 1.3 are both affected by this.

Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.

Actually, decided to take a look to it, and I think the answer for 1.1 (and thereby 1.2 potentially) may be wrong. That thing is pure pointer arithmetic which should be well defined really

Yes, it should be well defined, but it's not (maybe this has changed in C++11, I've not re-checked the spec). You're allowed to point to "one past the end" of an array, but no further than that.In practice, it works fine, but a compliant compiler is allowed to do whatever it likes if you ask for a pointer that's "two past the end" of an array.

It's basically inherited from C, which was developed in a time when computers were sufficiently low on memory that they literally couldn't fit all the symbols necessary for a complex program in memory all at the same time and still have room for actual code. Programmers would be able to identify which symbols were really needed and include only those headers.

Thank you, though I should have been more clear in indicating that I do understand the reason, but simply cannot stand the additional handling complexity. Of course it has its raison d'etre even today (embedded systems come to mind), but I might see the language in a more positive light if the .h/.c(pp) separation wasn't all but mandatory when targeting systems with plenty of resources. My apologies.

Interesting.The clear separation of a declaration and an implementation is one of the things I really like with C and C++.The header file has (should have) everything I need as a _user_ of the class, and nothing more. Makes the intention of the class very clear, and then I can "hide" the implementation in a cpp file.

Also, this separation is not mandatory, if you want, you can write everything in the same file too. Just gets more messy I really dislike how Java forces me to put everything in the same file...Very hard to get an overview of the class without additional tools like a smart IDE or doxygen...

People who dislike the compilation model may want to look out for (or even give feedback to the standards committee on) proposals for Modules. There have been proposals mentioning partial classes for easier code-gen tooling as well, but I don't know whether this is part of the Modules working group or separate at this point.

Actually, decided to take a look to it, and I think the answer for 1.1 (and thereby 1.2 potentially) may be wrong. That thing is pure pointer arithmetic which should be well defined really

Yes, it should be well defined, but it's not (maybe this has changed in C++11, I've not re-checked the spec). You're allowed to point to "one past the end" of an array, but no further than that.In practice, it works fine, but a compliant compiler is allowed to do whatever it likes if you ask for a pointer that's "two past the end" of an array.

All true. Although probably no compiler is going to give you trouble for this one, I was recently surprised when gcc turned this code into an infinite loop:

for (int i = 0; i >= 0; ++i) {
}

A more naive compiler would stop once i overflows and becomes a large negative number, but what happens after overflow is undefined behavior, so the compiler can assume that it won't happen (if it does, it's allowed to do anything it wants so any behavior is correct) and can therefore optimize `i >= 0' to `true'.

This kind of strict interpretation of the standard by the compiler makers is annoying. For instance, a C++98-compliant compiler can put an infinite loop at the end of a hello-world program, because the standard doesn't specify "finishing in a finite amount of time" as part of the observable behavior of the program. The return value of the program is also not part of the observable behavior, so I think a compiler could stay compliant while returning 3 from main every time, regardless of what the code says. Of course nobody would use a compiler that did that, but it illustrates the point that simply satisfying the standard is a low bar and I expect my compiler to be more reasonable than that.

Yeah, GCC generates that kind of code on purpose. Try to check for overflow after the fact (e.g. by checking if the value went negative), GCC will explicitly optimize out (i.e. remove) the check. The reasoning behind this is that "it's undefined behavior so we'll try to break the code so you can't rely on it", except sometimes that can backfire since that kind of bugs on purpose may not pop up in ages, depending on the situation.

Gotta admit I didn't think of that one. That's really annoying. (then again, why would you have a function overloaded both to an integer and a pointer at the same time?)

Yeah, GCC generates that kind of code on purpose. Try to check for overflow after the fact (e.g. by checking if the value went negative), GCC will explicitly optimize out (i.e. remove) the check. The reasoning behind this is that "it's undefined behavior so we'll try to break the code so you can't rely on it", except sometimes that can backfire since that kind of bugs on purpose may not pop up in ages, depending on the situation.

It takes a bit of a sadist to come up with that method to educate programmers.

How about a warning saying something like "this conditional expression evaluates to true unless you invoke undefined behavior"? If I am compiling some old piece of code that is now broken because the compiler is now a lawyer, I would much rather get an informative message than a bug.

From what I've heard, it wasn't a deliberate attempt to punish people who rely on undefined behavior, but just a consequence of a change to the optimizer to generate faster code. It just so happens that it looks like an attempt to piss off people who rely on undefined behavior. Fortunately, gcc offers a flag to disable this optimization: -fwrapv.

Anyways, for a less contrived example of overloading a pointer and an integer:

ostream & operator<<(int);
ostream & operator<<(const void *);
// along with half a million other member overloads and some non-member overloads

Interesting.The clear separation of a declaration and an implementation is one of the things I really like with C and C++.The header file has (should have) everything I need as a _user_ of the class, and nothing more.Makes the intention of the class very clear, and then I can "hide" the implementation in a cpp file.

Except that the header file also contains information about private member variables and methods. So you either give the client all the details about the class, or you end up using something like pimpl, which is yet another hoop to jump through that other languages have realised provides no tangible benefit.

Also, this separation is not mandatory, if you want, you can write everything in the same file too. Just gets more messy I really dislike how Java forces me to put everything in the same file...Very hard to get an overview of the class without additional tools like a smart IDE or doxygen...

So? This isn't the 80's anymore. We don't have to program in vi and cc on the command line. Realistically, managing any project of a decent size without an IDE is just making work for no reason.

if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight

At least recent versions of g++ give you a reasonable warning about this one.

I ran into one of these on a function call in optimised code where the compiler had optimised away the actual instance we were interested in being passed to the function, that was a fun few days to track that down.