Exception specification as part of the type system
A prvalue of type “pointer to noexcept function” can be converted to a prvalue of type “pointer to function”. The result is a pointer to the function. A prvalue of type “pointer to member of type noexcept function” can be converted to a prvalue of type “pointer to member of type function”. The result points to the member function.
Example:
1 2 3 4 |
void (*p)() throw(int); void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function struct S { typedef void (*p)(); operator p(); }; void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept function |
This feature affects valid C++14 code. For example:
1 2 3 4 5 |
void g1() noexcept; void g2(); template<class T> int f(T *, T *); int x = f(g1, g2); |
Works in C++14 and fails in C++17.
Related standard document: p0012r1.
Dynamic memory allocation for over-aligned data
Simplify use of over-aligned types. In C++17 was added new operator new:
1 |
void* operator new(std::size_t, std::align_val_t); |
Which will be called in case when we have custom align for struct or class. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class alignas(32) CustomFloat { public: float f[3]; void* operator new(std::size_t size) { std::cout << "operator new()" << std::endl; return malloc(size); } void* operator new(std::size_t size, std::align_val_t) { std::cout << "operator new2()" << std::endl; return malloc(size); } }; CustomFloat* f = new CustomFloat(); // will be called second new operator |
In case without alignas will be called first new operator.
Related standard document: p0035r4.
Stricter order of expression evaluation
The order of evaluation of certain subexpressions has been specified more than it used to be. An important particular aspect of this change is that function arguments are now evaluated in an indeterminate order (i.e. no interleaving), which was previously merely unspecified.
New rules:
– Postfix expressions are evaluated from left to right.
– This includes functions calls and member selection expressions.
– Assignment expressions are evaluated from right to left.
– This includes compound assignments.
– Operands to shift operators are evaluated from left to right.
In summary, the following expressions are evaluated in the order a, then b, then c, then d:
1. a.b
2. a->b
3. a->*b
4. a(b1, b2, b3)
5. b @= a
6. a[b]
7. a << b
8. a >> b
Additional rule: the order of evaluation of an expression involving an overloaded operator is determined by the order associated with the corresponding built-in operator, not the rules for function calls.
Undefined behavior
1) If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.
1 2 3 4 5 |
i = ++i + 2; // undefined behavior until C++11 i = i++ + 2; // undefined behavior until C++17 f(i = -2, i = -2); // undefined behavior until C++17 f(++i, ++i); // undefined behavior until C++17, unspecified after C++17 i = ++i + i++; // undefined behavior |
2) If a side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object, the behavior is undefined.
1 2 3 |
cout << i << i++; // undefined behavior until C++17 a[i] = i++; // undefined behavior until C++17 n = ++i + i; // undefined behavior |