I was C++ dev for 5 or 6 years, up to the late 2000s.
I got another C++ job about 3 years ago but bailed after about a year.
I could write a tome about what I dislike but to start with, any language that lacks a working standard built-in string type, is just a hard no for me at this stage in my life. Life is just too short.
The tooling and IDE support is atrocious, no standard dependency management for 3rd party libraries and CMake makes maven look well designed.
I tried to pull my knowledge up to date. Hmmm, we used to have lvalues and rvalues, what's this prvalue thing?
Surely cppreference can explain:
> a prvalue (“pure” rvalue) is an expression whose evaluation
> - computes the value of an operand of a built-in operator (such prvalue has no result object), or
> - initializes an object (such prvalue is said to have a result object).
> * The result object may be a variable, an object created by new-expression, a temporary created by temporary materialization, or a member thereof. Note that non-void discarded expressions have a result object (the materialized temporary). Also, every class and array prvalue has a result object except when it is the operand of decltype;*
> The following expressions are prvalue expressions:
> a literal (except for string literal), such as 42, true or nullptr;
> a function call or an overloaded operator expression, whose return type is non-reference, such as str.substr(1, 2), str1 + str2, or it++;
> a++ and a--, the built-in post-increment and post-decrement expressions;
> a + b, a % b, a & b, a << b, and all other built-in arithmetic expressions;
> a && b, a || b, !a, the built-in logical expressions;
> a < b, a == b, a >= b, and all other built-in comparison expressions;
> &a, the built-in address-of expression;
> a.m, the member of object expression, where m is a member enumerator or a non-static member function[2];
> p->m, the built-in member of pointer expression, where m is a member enumerator or a non-static member function[2];
> a.*mp, the pointer to member of object expression, where mp is a pointer to member function[2];
> p->*mp, the built-in pointer to member of pointer expression, where mp is a pointer to member function[2];
> a, b, the built-in comma expression, where b is an prvalue;
> a ? b : c, the ternary conditional expression for certain b and c (see definition for detail);
> a cast expression to non-reference type, such as static_cast<double>(x), std::string{}, or (int)42;
> the this pointer;
> an enumerator;
> a non-type template parameter of a scalar type;
> a lambda expression, such as [](int x){ return x * x; };
> (since C++11)
> a requires-expression, such as requires (T i) { typename T::type; };
> a specialization of a concept, such as std::equality_comparable<int>.
> (since C++20)
> Properties:
> Same as rvalue (below).
> A prvalue cannot be polymorphic: the dynamic type of the object it denotes is always the type of the expression.
> A non-class non-array prvalue cannot be cv-qualified, unless it is materialized in order to be bound to a reference to a cv-qualified type(since C++17). (Note: a function call or cast expression may result in a prvalue of non-class cv-qualified type, but the cv-qualifier is generally immediately stripped out.)
> A prvalue cannot have incomplete type (except for type void, see below, or when used in decltype specifier).
> A prvalue cannot have abstract class type or an array thereof.
Yeah, this language is loads of fun. I've worked on compilers, interpreters, implemented extended Hindley-Milner type systems, etc. so normally love reading formal language specs but this is just insane.
A wafer thin wrapper around an array of bytes using null termination - a model of "strings" which is effectively a computer technology fossil - nearly 60 years old at this stage.[1]
It contains no specified or implied encoding - so there is way to actually interpret the data as characters which I guess wasn't a problem in the age before computer networking - your machine has an encoding built in and that was how you interpreted bytes as characters.
A representation that, to save a byte or two at the header, means that determining the length of the string is an O(n) operation.
It's an abstraction so leaky, it's hard to see the advantage over const char* and the leaks can never be plugged given it's part of the spec that c_str() must run in constant time.
It's basically a dangling pointer generator with no unicode or any sort of internationalization support.
But why provide a usable string class (never mind any sort of usable date/timestampe representations) when the language designers can spend years to add a whole new layer of absolutely useless complexity to the language - like concepts, for example.
I got another C++ job about 3 years ago but bailed after about a year.
I could write a tome about what I dislike but to start with, any language that lacks a working standard built-in string type, is just a hard no for me at this stage in my life. Life is just too short.
The tooling and IDE support is atrocious, no standard dependency management for 3rd party libraries and CMake makes maven look well designed.
I tried to pull my knowledge up to date. Hmmm, we used to have lvalues and rvalues, what's this prvalue thing?
Surely cppreference can explain:
> a prvalue (“pure” rvalue) is an expression whose evaluation
> - computes the value of an operand of a built-in operator (such prvalue has no result object), or
> - initializes an object (such prvalue is said to have a result object).
> * The result object may be a variable, an object created by new-expression, a temporary created by temporary materialization, or a member thereof. Note that non-void discarded expressions have a result object (the materialized temporary). Also, every class and array prvalue has a result object except when it is the operand of decltype;*
> The following expressions are prvalue expressions:
> a literal (except for string literal), such as 42, true or nullptr;
> a function call or an overloaded operator expression, whose return type is non-reference, such as str.substr(1, 2), str1 + str2, or it++;
> a++ and a--, the built-in post-increment and post-decrement expressions;
> a + b, a % b, a & b, a << b, and all other built-in arithmetic expressions;
> a && b, a || b, !a, the built-in logical expressions;
> a < b, a == b, a >= b, and all other built-in comparison expressions;
> &a, the built-in address-of expression;
> a.m, the member of object expression, where m is a member enumerator or a non-static member function[2];
> p->m, the built-in member of pointer expression, where m is a member enumerator or a non-static member function[2];
> a.*mp, the pointer to member of object expression, where mp is a pointer to member function[2];
> p->*mp, the built-in pointer to member of pointer expression, where mp is a pointer to member function[2];
> a, b, the built-in comma expression, where b is an prvalue;
> a ? b : c, the ternary conditional expression for certain b and c (see definition for detail);
> a cast expression to non-reference type, such as static_cast<double>(x), std::string{}, or (int)42;
> the this pointer;
> an enumerator;
> a non-type template parameter of a scalar type;
> a lambda expression, such as [](int x){ return x * x; };
> (since C++11)
> a requires-expression, such as requires (T i) { typename T::type; };
> a specialization of a concept, such as std::equality_comparable<int>.
> (since C++20)
> Properties:
> Same as rvalue (below).
> A prvalue cannot be polymorphic: the dynamic type of the object it denotes is always the type of the expression.
> A non-class non-array prvalue cannot be cv-qualified, unless it is materialized in order to be bound to a reference to a cv-qualified type(since C++17). (Note: a function call or cast expression may result in a prvalue of non-class cv-qualified type, but the cv-qualifier is generally immediately stripped out.)
> A prvalue cannot have incomplete type (except for type void, see below, or when used in decltype specifier).
> A prvalue cannot have abstract class type or an array thereof.
Yeah, this language is loads of fun. I've worked on compilers, interpreters, implemented extended Hindley-Milner type systems, etc. so normally love reading formal language specs but this is just insane.