Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
58
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 133: Storage class specifiers

Storage class specifiers are keywords that can be used in declarations. They do not a ect the type of the declaration, but typically modify the way in which the entity is stored.

Section 133.1: extern

The extern storage class specifier can modify a declaration in one of the three following ways, depending on context:

1.It can be used to declare a variable without defining it. Typically, this is used in a header file for a variable that will be defined in a separate implementation file.

// global scope

 

int x;

// definition; x will be default-initialized

extern int y;

// declaration; y is defined elsewhere, most likely another TU

extern int z = 42; // definition; "extern" has no effect here (compiler may warn)

2.It gives external linkage to a variable at namespace scope even if const or constexpr would have otherwise caused it to have internal linkage.

// global scope

 

 

const int

w = 42;

// internal linkage in C++; external linkage in C

static

const int x = 42;

// internal linkage

in both C++ and C

extern

const int y = 42;

// external linkage

in both C++ and C

namespace

{

 

 

extern const int z = 42; // however, this has internal linkage since // it's in an unnamed namespace

}

3.It redeclares a variable at block scope if it was previously declared with linkage. Otherwise, it declares a new variable with linkage, which is a member of the nearest enclosing namespace.

// global scope namespace {

int x = 1; struct C {

int x = 2; void f() {

extern int x; // redeclares namespace-scope x std::cout << x << '\n'; // therefore, this prints 1, not 2

}

};

}

void g() {

extern int y; // y has external linkage; refers to global y defined elsewhere

}

A function can also be declared extern, but this has no e ect. It is usually used as a hint to the reader that a

function declared here is defined in another translation unit. For example:

void f(); // typically a forward declaration; f defined later in this TU extern void g(); // typically not a forward declaration; g defined in another TU

GoalKicker.com – C++ Notes for Professionals

636

In the above code, if f were changed to extern and g to non-extern, it would not a ect the correctness or semantics of the program at all, but would likely confuse the reader of the code.

Section 133.2: register

Version < C++17

A storage class specifier that hints to the compiler that a variable will be heavily used. The word "register" is related to the fact that a compiler might choose to store such a variable in a CPU register so that it can be accessed in fewer clock cycles. It was deprecated starting in C++11.

register int i = 0; while (i < 100) {

f(i);

int g = i*i; i += h(i, g);

}

Both local variables and function parameters may be declared register. Unlike C, C++ does not place any restrictions on what can be done with a register variable. For example, it is valid to take the address of a register variable, but this may prevent the compiler from actually storing such a variable in a register.

Version ≥ C++17

The keyword register is unused and reserved. A program that uses the keyword register is ill-formed.

Section 133.3: static

The static storage class specifier has three di erent meanings.

1. Gives internal linkage to a variable or function declared at namespace scope.

// internal function; can't be linked to

static double semiperimeter(double a, double b, double c) { return (a + b + c)/2.0;

}

// exported to client

double area(double a, double b, double c) { const double s = semiperimeter(a, b, c); return sqrt(s*(s-a)*(s-b)*(s-c));

}

2.Declares a variable to have static storage duration (unless it is thread_local). Namespace-scope variables are implicitly static. A static local variable is initialized only once, the first time control passes through its definition, and is not destroyed every time its scope is exited.

void f() {

static int count = 0;

std::cout << "f has been called " << ++count << " times so far\n";

}

3. When applied to the declaration of a class member, declares that member to be a static member.

struct S {

static S* create() {

GoalKicker.com – C++ Notes for Professionals

637

return new S;

}

};

int main() {

S* s = S::create();

}

Note that in the case of a static data member of a class, both 2 and 3 apply simultaneously: the static keyword both makes the member into a static data member and makes it into a variable with static storage duration.

Section 133.4: auto

Version ≤ C++03

Declares a variable to have automatic storage duration. It is redundant, since automatic storage duration is already the default at block scope, and the auto specifier is not allowed at namespace scope.

void f() {

auto int x; // equivalent to: int x;

auto y; // illegal in C++; legal in C89

}

auto int z; // illegal: namespace-scope variable cannot be automatic

In C++11, auto changed meaning completely, and is no longer a storage class specifier, but is instead used for type deduction.

Section 133.5: mutable

A specifier that can be applied to the declaration of a non-static, non-reference data member of a class. A mutable member of a class is not const even when the object is const.

class C { int x;

mutable int times_accessed; public:

C(): x(0), times_accessed(0) {

}

int get_x() const {

++times_accessed; // ok: const member function can modify mutable data member return x;

}

void set_x(int x) { ++times_accessed; this->x = x;

}

};

Version ≥ C++11

A second meaning for mutable was added in C++11. When it follows the parameter list of a lambda, it suppresses the implicit const on the lambda's function call operator. Therefore, a mutable lambda can modify the values of entities captured by copy. See mutable lambdas for more details.

std::vector<int> my_iota(int start, int count) { std::vector<int> result(count); std::generate(result.begin(), result.end(),

[start]() mutable { return start++; });

return result;

GoalKicker.com – C++ Notes for Professionals

638

}

Note that mutable is not a storage class specifier when used this way to form a mutable lambda.

GoalKicker.com – C++ Notes for Professionals

639