Show Lecture.Attributes as a slide show.
CS253 Attributes
Attribute | Value |
Name | Logan |
Class | College of Teaching Bard |
Alignment | Neutral Good |
Strength | 10 |
Intelligence | 18 |
Dexterity | 16 |
Sarcasm | 12 |
Wit | 18 |
Memory | 08 |
Attributes
Attributes add extra information to a variable, function, type, or statement.
Attributes look like: [[
attribute-name]]
or [[
attribute-name("
reason ")]]
[[deprecated]]: discourage the use of a variable or function, with an
optional reason given. “Deprecated” means support will be withdrawn
soon—stop using it.
[[deprecated]] int kansas() { return 35; }
[[deprecated("one-star rating")]] int texas = 28;
int main() {
return kansas() + texas;
}
c.cc:6: warning: ‘int kansas()’ is deprecated
c.cc:1: note: declared here
c.cc:6: warning: ‘texas’ is deprecated: one-star rating
c.cc:3: note: declared here
Deprecation examples
// Compiled under C++ 2014
bool printed = false;
if (!printed++) // 🦡
cout << "Bill";
c.cc:3: warning: use of an operand of type ‘bool’ in ‘operator++’ is
deprecated
Bill
// Compiled under C++ 2017
bool printed = false;
if (!printed++) // 🦡
cout << "Ted";
c.cc:3: error: use of an operand of type ‘bool’ in ‘operator++’ is
forbidden in C++17
In the bad old days, we incremented bool vars to make ’em true.
Postincrement was a cheap way to test the old value while setting
it to true.
Deprecation examples
- The functions bind1st() and bind2nd() were deprecated in C++2011,
because the general function bind() does their job better.
- They remained deprecated in C++2014.
- They were removed in C++2017.
int n = 0;
switch (n) {
case 0:
cout << "0\n";
[[fallthrough]];
case 2:
cout << "even\n";
break;
case 1:
cout << "1\n"; // 🦡
case 3:
cout << "odd\n";
}
c.cc:10: warning: this statement may fall through
c.cc:11: note: here
0
even
- The compiler complains about
case 1:
falling through into
case 3:
but is ok with case 0:
falling through into
case 2:
.
- We might forget the break at the end of a case
in a switch.
- Modifies a null statement with a semicolon.
[[maybe_unused]]: don’t complain that a type, variable, argument,
or function isn’t being used.
int main(int argc, char *argv[]) {
// argc, shmargc!
cout << "program name: " << argv[0];
return 0;
}
c.cc:1: warning: unused parameter ‘argc’
program name: ./a.out
https://wikipedia.org/wiki/Shm-reduplication
int main([[maybe_unused]] int argc, char *argv[]) {
cout << "program name: " << argv[0] << '\n';
return 0;
}
program name: ./a.out
In this case, it would have been better to simply omit the name of
the argument:
int main(int, char *argv[]) {
cout << "program name: " << argv[0] << '\n';
return 0;
}
program name: ./a.out
or, if the name has mnemonic value, place it in a
/*
comment */
:
int main(int /* argc */, char *argv[]) {
cout << "program name: " << argv[0] << '\n';
return 0;
}
program name: ./a.out
[[nodiscard]]: the return value must be used.
int foo() {
return 1;
}
[[nodiscard]] int bar() {
return 2;
}
int main() {
foo();
bar();
}
c.cc:11: warning: ignoring return value of ‘int bar()’, declared with
attribute ‘nodiscard’
c.cc:5: note: declared here
This isn’t the default, because many functions do something
and also return an error indication or status.
Ignoring the return value is ok, in certain contexts.
Novices confuse vector::clear() and vector::empty().
As of C++20, vector::empty() is marked [[nodiscard]],
so incorrect use is flagged:
vector v = {11,22,33};
v.empty(); // 🦡 clear values (Oops!)
cout << v.size() << '\n';
c.cc:2: warning: ignoring return value of ‘bool std::vector<_Tp,
_Alloc>::empty() const [with _Tp = int; _Alloc = std::allocator<int>]’,
declared with attribute ‘nodiscard’
In file included from /usr/local/gcc/11.2.0/include/c++/11.2.0/vector:67,
from /usr/local/gcc/11.2.0/include/c++/11.2.0/functional:62,
from /usr/local/gcc/11.2.0/include/c++/11.2.0/pstl/glue_algorithm_defs.h:13,
from /usr/local/gcc/11.2.0/include/c++/11.2.0/algorithm:74,
from /usr/local/gcc/11.2.0/include/c++/11.2.0/x86_64-pc-linux-gnu/bits/stdc++.h:65,
from /s/bach/a/class/cs000/public_html/pmwiki/cookbook/c++-includes.h:7,
from <command-line>:
/usr/local/gcc/11.2.0/include/c++/11.2.0/bits/stl_vector.h:1007: note: declared
here
3
It would be swell if [[nodiscard]] caught this, but it doesn’t.
class Point {
public:
Point(int a, int b) : x(a), y(b) { };
int x, y;
};
Point(3,5); // Create & discard an unnamed Point
It would help those who don’t understand C++ constructor delegation.
void depart() { exit(1); }
int foo() {
if (getpid() == 0) // no root!
depart();
else
return 4;
}
int main() {
cout << "Hello, world!\n";
return foo();
}
c.cc:5: warning: control reaches end of non-void function
Hello, world!
The compiler is concerned that, after depart()
returns, foo()
will have no return value. We know that depart()
won’t return,
but the compiler couldn’t know that if depart()
were in a separate
source file.
[[noreturn]] indicates that a function does not return.
[[noreturn]] void depart() { exit(1); }
int foo() {
if (getpid() == 0) // no root!
depart();
else
return 4;
}
int main() {
cout << "Hello, world!\n";
return foo();
}
Hello, world!
Now, the compiler is happy.