Show Lecture.Attributes as a slide show.
CS253 Attributes
Attribute | Value |
Name | Jack |
Class | Teacher |
Alignment | Lawful Good |
Strength | 8 |
Dexterity | 6 |
Constitution | 7 |
Intelligence | 12 |
Wisdom | 13 |
Charisma | 8 |
Sarcasm | 18 |
Attributes
Attributes add extra information to a variable, function, type, or statement.
Attributes look like this: [[
attribute-name]]
or [[
attribute-name("
reason ")]]
[[deprecated]]: discourage the use of a variable or function,
with an optional reason given.
[[deprecated]] int foo() { return 1; }
[[deprecated("useless")]] int n = 2;
int main() {
return foo()+n;
}
c.cc:5: warning: 'int foo()' is deprecated
c.cc:1: note: declared here
c.cc:5: warning: 'int foo()' is deprecated
c.cc:1: note: declared here
c.cc:5: warning: 'n' is deprecated: useless
c.cc:2: note: declared here
In compiler jargon, “deprecated” means support will be withdrawn soon,
so stop using it.
The fuctions bind1st() and bind2nd() are deprecated, because the general
function bind() does their job better. They still exist now, but might
not in the next version of C++. g++ might still provide them after
they’re removed from the standard to help people with old programs, or
it might simply remove them from the implementation.
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:
.
- Coders sometimes forget the break at the end of a case
in a switch statement.
- 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:6: warning: ignoring return value of 'int bar()', declared with attribute
nodiscard
c.cc:2: 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<int> v = {11,22,33};
v.empty(); // clear values (Oops!)
cout << v.size() << '\n';
3
Once we get a C++20 compiler on this web server, you’ll see it.
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() { throw "Goodbye"; }
int foo() {
if (getpid() == 0) // no root!
depart();
else
return 4;
}
int main() {
cout << "Hello, world!\n";
return foo();
}
c.cc:8: 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 wouldn’t know that if depart()
were in a separate
source file.
[[noreturn]] indicates that a function does not return.
[[noreturn]] void depart() { throw "Goodbye"; }
int foo() {
if (rand() < 100)
depart();
else
return 4;
}
int main() {
cout << "Hello, world!\n";
return foo();
}
Hello, world!
Now, the compiler is happy.