Obscure C++ Features
madebyevan.com
madebyevan.com
Though I agree that some of the given examples should be clear by reading a good C++ book, which is one of the main issue with learning C++, most of the books aren't really good enough.
What has Rust to show besides Servo?
Note, I do like Rust as well.
But the result will no longer be C++ for better and worse.
I think C++ usage is one of those things that you don't truly understand until you've decided to start a new project in C++ even in 2013. For a reasonably common feature set in real project (i.e. not a side project for fun), C++ is the only option.
Specifically most alternatives exhibit one or more of the following:
* automatically managed memory (enough said)
* not expressive enough (I would throw C in this category even though C is a fine choice and often times the best choice for many projects)
* not nearly mature enough in terms of compiler/toolset/language in general (often, it's unclear whether the language will ever achieve that necessary maturity)
* not fast enough, usually for one of the above reasons, but sometimes for other reasons
And I'd hardly label C++ as the epitome of expressiveness. A broad, haphazard feature set doesn't necessarily imply it's expressive.
But you can certainly have automatic memory management in C++ as well. Stack-allocated objects manage themselves, for dynamically allocated objects one can use scoped/shared pointers. One added perk is that you can extend this approach to deterministically manage not only memory, but any other resource that can be acquired and released (e.g. locks). I actually like this approach very much. The only problem I see there is that since you're still using raw pointers, the runtime can't really move things around for efficiency since that would invalidate the pointers. But in a garbage-collected language that doesn't expose pointers, the heap can be defragmented during runtime, which is nice.
The biggest downside is not really efficiency but that you lose the memory safety of a managed language doing this.
I wonder if it's possible to design a language that would be able to prevent these problems at compile time without incurring the runtime cost of managed languages. I mean, we already can detect some problems using static code checking tools (i.e. PVS-studio), so it must be feasible.
Rust does this. :) It is not easy to get right—the borrow checker required a lot of design work to achieve the right balance between expressiveness and practicality—but I think we've shown that it is possible.
(Disclaimer: I work on Rust.)
Arrays are bounded. You can usually disable bounds checking locally if you really need the extra ms, for cases the compiler is not able to optimize them.
Proper strings instead of char pointers that might be null terminated or not.
Var parameters and unbounded vector parameters to handle arguments that need to be changed.
Oberon family has already proven it is possible to write desktop operating systems in GC enabled systems programming languages.
Now as you say, many of these things are possible in modern C++. The problem is getting everyone on board, specially when dealing with old code bases littered with C like constructs.
Garbage collection has a ton of problems in systems applications (off the top of my head: unreasonable and unpredictable delays, incapability of dealing with a large amount of heap-allocated memory efficiently). Reference counting is better in many ways, but is not always appropriate and definitely has a cost (and I say this as someone who uses shared_ptr quite often).
Some people eschew Java and the JVM due to the spectre of garbage collection ruining their quasi-realtime system. But others embrace the JVM, organizing their programs to avoid garbage collection during critical times (which could last for hours or days).
With C and C++ it is the same, but backward: people flock to these languages for the predictable performance. Yet once there, they discover they must avoid the default allocator, for it is a source of unpredictable delays. Pooled allocators are created, and the end result is much the same as for the JVM folks.
http://en.cppreference.com/w/cpp/container/vector/reserve
If you want realtime guarantees, you have a lot more unpredictable problems, like CPUs having cache.
Not always. If we have a loop that calls our append_10_items_to_vector N times (on the same vector), then your reserve() just transformed the loop into O(N^2) code. Without reserve, it would be O(N).
As a rule of thumb, use reserve only if you are really sure that nobody's ever going to add anything more to your vector in the future.
However, almost always, somebody has to write that database code and the code that displays the nicely formatted data (like in actually lighting pixels on the screen instead of filling out some css properties) and even the code that takes the user input. And for these purposes managed memory is a disaster and C++ is the most expressive language available.
IMHO, managed memory for system-level code is nowhere near being a "disaster". It might be sometimes tricky to get right, but not any harder than getting manual memory management right in C++ (and smart_pointers aren't a silver bullet, neither). Additionally, there are some Java extensions that let you write real-time code in it and guarantee GC won't kick in when you don't want it to.
I write code that I consider system level (it talks to the hardware directly) and "tricky" is quite an understatement. Starting from the fact that there are half a dozen types of memory (not even talking about memory-mapped I/O) and just one "heap" in Java. Not to mention the hardware is not aware about the awesomeness of JVM and is trying to read/write actual memory pointers. I can imagine that you could get around this (as well as the lack of bit-fields and unsigned types) through some kind of memory-mapped-as-a-file trick but at this point you are not using the memory management at all. And IMHO this is very far from being "not any harder" than using pointers in C++.
You'd been saying that in your humble opinion system programming in Java is no harder than in C++, which is something very alien to my experience of actually programming on the system level (as same as your performance claims but I am not even going to get into this one. Last time I did a Java programmer told me that a Java program that is measuring as 4 times slower is running "on the same level", whatever that means).
As of performance, they are doing extremely well. Last time I checked Netty vs Nginx was a tie; Tomcat vs Apache HTTP were also extremely close; Apache Spark (pure Java) is generally much faster than Impala (using C++); and Cassandra has no direct competitors written in C++ so far (not counting 1000 toy databases here), but it is definitely one of the top performant NoSQL stores out there.
For the concrete addresses you just link with the symbols defined outside of your C code. Special ops cannot be done in pure standard, but this is not an issue in practice as there are no pure standard compilers. Even for app development you want intrinsics just for the vector, cache and bit instructions.
You need an external Assembler or OS APIs to provide the required functionality. The same way that a Java runtime library can provide bindings to Assembly or OS APIs.
There are commercial AOT native compilers for Java targeting systems programming, like the ones from Atego.
Many mainstream languages, with AOT native compilers would be as usable.
Do you write portable code in C and C++ across disparate systems and OSs, using multiple compilers?
I used to do that between 1994 and 2001. Don't miss those days of hit-and-miss about compiler support.
> We did not have a standard till 1998, yet somehow managed to use C++.
Yes we did. It was called the Annotated Reference Manual, used as basis for the standard, coupled with articles from The C++ Report, The C Users Journal (latter The C/C++ Users Journal).
> Same as with C, which had been used very successfully standard-less for almost two decades.
It works if you only care about one specific compiler. On those days the standard was the AT&T UNIX compiler.
And then you realize it's not a big deal. Changes between platforms are greater than changes between compilers. When your targets have different endianness or, even better, mixed endianness between different PUs - the standard compliance of your code is the least of your worries.
>It works if you only care about one specific compiler.
Also works if you care about a finite number of specific compilers and architectures.
>On those days the standard was the AT&T UNIX compiler.
There were, probably, hundreds of compilers and C flavors even before the ANSI C. What one thought was "the standard" was very subjective.
Sure, but the goal is to minimize system dependencies as much as possible.
Relying on language extensions works against it.
> There were, probably, hundreds of compilers and C flavors even before the ANSI C. What one thought was "the standard" was very subjective.
Yes, I do remember variants like Small C.
Excuse me but what??? Please give an example. Except for maybe setting up an isr vector table and the odd coprocessor command in assembler, all other peripheral functionality is usually memory mapped and perfectly accessible in C and C++.
As of XNU, it is mostly pure C. There are a few C++ files there but they are very far from what we call "modern C++". No templates, no use of standard library, no exceptions, const char* everywhere. Just C with classes.
You are correct, C++ is a bad choice for low-level device drivers. But it's getting better [1]!
[1] http://msdn.microsoft.com/en-us/windows/hardware/gg487420.as...
But when you're working in a constrained environment, you need the option to control all this in much detail. C++ is one of the very few options you have for that.
I agree that if your memory management is dead simple and you are fine with using only unique_ptr everywhere, C++ solution is superior. You obviously don't need GC, so why pay for it. Probably C would do just as fine, assuming you have some static analysis tool to find all the forgotten free calls.
However, there are some domains where GC enables completely different ways of programming. E.g. lockless concurrency / immutable structures / functional programming etc. Poor shared_ptr performance and scalability is prohibitive in those areas.
I don't believe such a static analysis tool can exist without being a different language (e.g. Cyclone). There just isn't enough information about ownership semantics in C's type system.
[1] http://static.rust-lang.org/doc/0.8/rust.html#memory-boxes
While it helps, it can only cover the code you have access to.
No way to take care of third party libraries delivered in binary form.
Java's pointer might be faster than shared_ptr. But, in Java, all objects are held by pointers. C++ gives you more options. It's not like we're going "Damn, I just can't figure out the ownership here. I'll just use shared_ptr and be done with it" every day. In my experience, usage of shared_ptr is quite limited.
shared_ptr use is limited because shared_ptr is slow and people learned to avoid it at all cost. But having to think about ownership influences design choices and often makes things more complex and less performant that needed (e.g. it often forces to copy objects instead to just pass a pointer).
You can keep extolling the virtues of Java performance, but fact remains that Java doesn't see much use in areas where performance is critical. It doesn't mean Java doesn't have a use, it's just not there.
Maybe this is the reason C++ guys always complicate things: http://www.johndcook.com/blog/2011/06/14/why-do-c-folks-make...
As of Java being not-performant enough: that's why Java is used as one of the most popular language for implementation of modern NoSQL databases systems. Everyone knows performance doesn't matter in databases. ;)
without these i have very few leaks or problems - and when i do they are trivial to find and fix. i see the advantage for RAD, but for performance and memory critical code these things are actually dangerous and stupid imo. measurably so...
Mastering C++ is like playing guitar, but most corporate developers only know how to play Kazoo.
"not nearly mature enough in terms of compiler/toolset/language in general (often, it's unclear whether the language will ever achieve that necessary maturity)"
in that list. One of my perennial complaints about C++ is that it seems to be a moving target[1], more so than I really want to expose serious work to.
Like the issues numbered 1, 3, 4, 6.
i constantly want something better than C - something where the compiler has freedom to optimise my memory layout with a keyword for types that have to cross boundaries. something with metaprogramming built in. something where const is not just a promise, but the law etc...
Also "C is quirky, flawed, and an enormous success" Denis Ritchie.
Security does not necessarily always matter when you're programming something, it does when you make widely used libraries or application or drivers or an OS, which are done by experts and tightly reviewed, so the language is not an issue.
Sometime you'll need pure performance or very low power consumption, and there will be no concerns of security between there will absolutely no way to compromise it (no "vector").
Security is not a particular feature of any particular programming language anyways, every program, whatever the language, is subject to security concern, it's not a language concern.
Yes.
Although the insecure design of C and C++ (thanks to its C underpinnings) are just an attack vector from many possible ones, it is quite easy to get exploited thanks to the skills of many people writing applications on those languages.
Removing away the possibility of out of bounds errors and pointer misuse, not possible in other safer systems programming languages, already removes away many of those attacks.
So nowadays we have to deal with compiling with -Wall -Wpedatic -Werror, coupled with valgrind like tools and static analyzers to achieve some level of confidence that undefined behaviors and pointer misuses are not creeping in the code.
You are right, this is only a small step in the whole security picture, there is also SQL injection, social engineering and many other forms of attacks. Still buffer overflow exploits remain one of the first forms of attack.
I do code in C++ since the ARM days, so I do know it quite well. Not making this argument as an anti-C++ zealot.
You can't have both performance AND remove the chances programmers will make mistakes. A tool is a tool with its compromises, you can't have all the advantages.
> Removing away the possibility of out of bounds errors and pointer misuse, not possible in other safer systems programming languages, already removes away many of those attacks.
Then don't use pointers, or learn how to use them properly. You should not hack into pointers anyway, there are never good reason to do so, both for risks of bugs and reduced code re-usability. STL containers make pointer use already quite almost irrelevant.
And if it's only C, not C++, I'd argue that C is quite an old system language. Security is an expensive feature, and you're free to code faster without minding security if the business you're doing allows it.
The better solution in all this, is using solutions like Cython, or make tools that allows easier bindings with C++ libraries. It doesn't change the fact that often, you'll need to optimize a part of your code, and you'll need to make a C/C++ library out of it, which you'll link against. All this process is quite not standard, and will cost time and learning, because it's quite painful. Security is often not worth the effort. Often it's much more easier to make sure users are using secure applications and securing your network and teaching users about security, than hire a security expert to review your code.
And by the way, if someone hack into your system and steal stuff, it's still a criminal act, it's not the fault of the guy who decided to use C++ because he needed speed.
Ada is a possible compromise. Modula-2 used to be one as well, before C got spread outside of UNIX.
> And if it's only C, not C++, I'd argue that C is quite an old system language. Security is an expensive feature, and you're free to code faster without minding security if the business you're doing allows it.
Yes, it is about C. C++ security flaws are a consequence of its C compatibility.
Nowadays security is a must for everything except toy programs.
> Nowadays security is a must for everything except toy programs.
I disagree. A program can be quite secure enough if you follow simple guidelines and/or use secure libraries, and you'll save a huge amount of money not hiring someone to inspect and approve your code. It also depend how your program is designed and what it does, design plays a huge part in security. There are many ways to avoid vulnerabilities like not connecting the hardware to the internet, disable USB connectivity, compartmentalize user lands, and so on.
If you're making an internet browser, an internet payment solution, a government website, of course you will try to pay a lot of money trying to reduce vectors the most you can, and try to not use C, but those project are specific and security is 90% of the work. If you're making an industrial robot, a car computer, a GPS-only device, a home thermostat, a cashier computer, it's not the programming language that will make a difference in security, it's the tools require to connect to those hardware that will make hacking it difficult.
A system will only be interesting to hack if it's both a mainstream device and if the infection vectors are easy to deal with. For example, ATM machine are never connected to the internet, they use dedicated communication lines.
My experience shows otherwise.
> For example, ATM machine are never connected to the internet, they use dedicated communication lines.
Yep, it really helps.
http://www.bubblews.com/news/353683-usa-atm039s-remotly-hack...
Right now I am coding a graphics algorithm in C++. So although I have this opinion, I am also pragmatic and use whatever tooling my customers ask for.
As for the rest, I guess we have to agree to disagree. :)
I honestly don't care about security at all. Arguing a language is not secure, is like saying you can cut yourself with a knife, and still people are stupid enough to hurt themselves with butter knives.
The only language that is truly secure is javascript, and you can't really do everything with it, one time or another, you need to access the hardware and write file.
C/C++ is a tradeoff, it's quite easy to teach, so you're very productive with it, that's one of the most important thing about a language, and it's still fast, but you need to use it carefully. Security has always been a costly, luxury feature that is really better to have in some cases, but if you're a small company and need to get something done, C/C++ is just great. And if you get hacked, most of the time, the guys who did it get caught, so I don't see why the industry should shift to ada or VM languages (which have been showed to have still many vulnerabilities).
"There are only two kinds of languages: the ones people complain about and the ones nobody uses" Bjarne Stroustrup
I've mostly written scripting languages until C++ but man C++11 has made the transition way easier. A lot of small stuff that makes your day so much better. Some big stuff that also makes your day better.
As a Pascal refugee that really enjoys the languages developed by Wirth for systems programming, I would rather see C and C++ replaced by something that was rather safe by default, unsafe only when really required.
Having said this, I do enjoy coding in C++, when I am able to work with developers of the same skill level that are able to fully code in modern C++ and not C compiled with a C++ compiler guys.
C++11 and C++14 are nice improvements to make the language better, that are just spoiled for the C historical baggage.
Now back to JVM/.NET land.
I was hating c++ for vague reasons I couldn't place. I was wrong.
Stroustrup wrote an interesting paper (wish I could find it) in IEEE/Computer magazine that strongly advocated static code and not overuse of dynamic_casts etc. for speedy programs - this is making the compiler do all of the optimization instead of doing everything/making many decisions at run time.
The Wikipedia article on C++11 covers many of the new features quite well, but Stroustrup's recent revision of the C++ book is a joy to read - the fonts help, as the previous one had some pretty horrible fonts in my opinion.
A weird case I found recently was that the VS2010 implementation of std::to_string(...) only supports long long, unsigned long long and long double. http://msdn.microsoft.com/en-us/library/ee404875(v=vs.100).a... Not very useful for most cases. Luckily VS2012+ supports the rest of the number types.
The funny thing is that "C++ as most people know it" is pretty far from "C++ as it was intended". Luckily, C++11 is nudging everyone towards the latter.
Q1: Is the following code legal C++?
string f() { return "abc"; }
void g() {
const string& s = f();
cout << s << endl; // can we still use the "temporary" object?
}
[1] http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the...eg is when you have a function like below:
void foo( const string& str )
{
cout << str ;
}
The above function takes a const reference to string and uses it without caring if the passed in variable is a temporary variable or not.Now declare a function as:
string bar() { return "abc" ; }
and the above two function can be used with: foo( bar() ) ;
I think this use case is the one that allowed the use of temporary variable from a const reference and people do this all the time.I think they did based on 8.5.3 which has this example:
struct A { };
struct B : public A { } b;
extern B f();
const A& rca = f(); // Either bound to the A sub-object of the B rvalue,
// or the entire B object is copied and the reference
// is bound to the A sub-object of the copy
As well as 12.2 para 5: class C {
// ...
public:
C();
C(int);
friend C operator+(const C&, const C&);
˜C();
};
C obj1;
const C& cr = C(16)+C(23);
C obj2;
In the C++ standard which talks about the temporary bound to cr existing for the duration of the entire program? Moreover, why would a rule for const references be specifically needed to handle foo( bar() );, but no equivalent rule for bar().foo(); which handles an implicit non-const pointer?In an indirect way though I agree: it is important for the language to make it easy to break apart complex expressions, but without this lifetime extension, I suspect it may not be possible to un-nest function calls without creating more copies (RVO may prove me wrong though - not studied the case in full).
const char *f() { return "abc"; }
void g() {
const char * s = f();
puts(s);
}
Nothing temporary is created at all. It's rather convenient.Hey, I remember when those were introduced!
I was the sysadmin responsible for supporting the default gcc on all of a computer science department's non-research machines and upgraded gcc between semesters. I then got to spend a couple of days rewriting some grad students' code because the had used "and" and "or" as variable names.[1]
Fun times!
[1] Many of whom were upset because the upgrade had changed the preprocessor/compiler interface and broke their research compiler.
In C, the first few are only if you include the C99 header <iso646.h> (the later ones are just digraphs). Are they included by default in C++?
Accessing an element of an array via ptr[3] is actually just short for *(ptr + 3).
This can be equivalently written as *(3 + ptr) and therefore as 3[ptr], which turns out to be completely valid code. BCPL C
!a *a
a ! 0 a[0]
0 ! a 0[a]
!(a + 0) *(a + 0)
!(0 + a) *(0 + a)
That’s where C got its 0-based semantics from—it would be a nasty surprise if 0 weren’t the identity for pointer addition!The title to that paragraph is miss leading, it's true for array but for a class brackets can do whatever the developer implements them to do.
typedef int F(int);
class C { F f; };
int C::f(int i) { return i; }
I've never seen it used in practice...the constructor vs. function choice is a classic gotcha for instance. i've had to explain it to juniors many times.