CS253: Software Development with C++

Fall 2020

Attributes

Show Lecture.Attributes as a slide show.

CS253 Attributes

AttributeValue
NameJack
ClassTeacher
Alignment Lawful Good
Strength8
Dexterity6
Constitution7
Intelligence12
Wisdom13
Charisma8
Sarcasm18

The attributes from my character sheet for this role-playing game.

Attributes

Attributes add extra information to a variable, function, type, or statement.

Attributes look like this: [[attribute-name]] or [[attribute-name("reason")]]

[[deprecated]]

[[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.

[[fallthrough]]: I meant to do that!

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

[[maybe_unused]]

[[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

Alternatives to [[maybe_unused]]

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]]

[[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.

[[nodiscard]]

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.

[[nodiscard]] failure

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.

[[noreturn]]

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]]

[[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.