Update: jduck pointed out that the before/after code snippets were identical. Oops. Now fixed.
I'd previously given up on C++ due to the many small frustrations: incomprehensible error messages, silly parsing issues (e.g. '>>'), rules to avoid subtle errors, and many other small frustrations that soured me on the language. That was back in the days of C++98 and C++03.
The language has evolved, and recently I found myself working on a project written in C++11. So far my experience has been better, but still frustrating.
I'll start with a real example. The project created a lot of Foo objects that were passed by reference to numerous functions. I needed to keep a collection of every Foo object that was passed to a specific function.
My first thought was, "I know, I'll create a vector of Foo&". This thought is simple, elegant, and of course, wrong.
A vector of references isn't possible because references can't be reassigned. That is, references[0] = foo; would update the referenced object, not the zeroth entry of the references vector. More technically, references are not CopyAssignable, a requirement for members of containers.
But how would someone new to C++ know this? What do compilers say when making a vector of references? Lets find out by compiling this small (and wrong) program.
Here are the results for Clang, GCC and MSVC:
In classic C++ style, the error messages are hundreds of error lines from obscure library implementation code. They give no indication of what is wrong, and no indication of the solution. I pity someone who doesn't have C++ experience trying to figure out what is wrong with their code. Pretty much any error would be more helpful, even an obscure message like "Member must be CopyAssignable" -- as long as it pointed out the correct line of code.
For reference, the corrected program is:
The fix is to use the std::reference_wrapper utility function when making a container of references.
There's definitely upsides: the '>>' parse has finally been fixed. Classes can now be initialized with initializer lists. There is type inference via 'auto'. For-each style loops exist.
C++11 is a great improvement over C++03, but its still frustrating: the obvious solution (like containers of references) is wrong in subtle ways, and compilers still generate hundreds of obscure error messages for a one-character typo.
I'd previously given up on C++ due to the many small frustrations: incomprehensible error messages, silly parsing issues (e.g. '>>'), rules to avoid subtle errors, and many other small frustrations that soured me on the language. That was back in the days of C++98 and C++03.
The language has evolved, and recently I found myself working on a project written in C++11. So far my experience has been better, but still frustrating.
A Motivating Example
I'll start with a real example. The project created a lot of Foo objects that were passed by reference to numerous functions. I needed to keep a collection of every Foo object that was passed to a specific function.
My first thought was, "I know, I'll create a vector of Foo&". This thought is simple, elegant, and of course, wrong.
A vector of references isn't possible because references can't be reassigned. That is, references[0] = foo; would update the referenced object, not the zeroth entry of the references vector. More technically, references are not CopyAssignable, a requirement for members of containers.
Errors Galore
But how would someone new to C++ know this? What do compilers say when making a vector of references? Lets find out by compiling this small (and wrong) program.
#include <vector> #include <iostream> int main(int argc, const char* argv[]) { int a = 1; std::vector<int&> test = {a}; std::cout << "a: " << test[0] << std::endl; return 0; }
Here are the results for Clang, GCC and MSVC:
Compiler | Error List | Error Count |
---|---|---|
Clang | rextester.com/JMFGP72087 | 158 lines |
GCC | rextester.com/HGKFIT84222 | 187 lines |
MSVC | rextester.com/UXPG39365 | 107 lines |
In classic C++ style, the error messages are hundreds of error lines from obscure library implementation code. They give no indication of what is wrong, and no indication of the solution. I pity someone who doesn't have C++ experience trying to figure out what is wrong with their code. Pretty much any error would be more helpful, even an obscure message like "Member must be CopyAssignable" -- as long as it pointed out the correct line of code.
The Fix
For reference, the corrected program is:
#include <vector> #include <iostream> #include <functional> int main(int argc, const char* argv[]) { int a = 1; std::vector<std::reference_wrapper<int>> test = {a}; std::cout << "a: " << test[0] << std::endl; return 0; }
The fix is to use the std::reference_wrapper utility function when making a container of references.
Conclusion
There's definitely upsides: the '>>' parse has finally been fixed. Classes can now be initialized with initializer lists. There is type inference via 'auto'. For-each style loops exist.
C++11 is a great improvement over C++03, but its still frustrating: the obvious solution (like containers of references) is wrong in subtle ways, and compilers still generate hundreds of obscure error messages for a one-character typo.
No comments:
Post a Comment