What are the best ways to declare and define global constants in C++? I am mostly interested in C++11 standard as it fixes a lot in this regard.
[EDIT (clarification)]: in this question "global constant" denotes constant variable or function that is known at compile time in any scope. Global constant must be accessible from more than one translation unit. It is not necessarily constexpr-style constant - can be something like const std::map<int, std::string> m = { { 1, "U" }, { 5, "V" } }; or const std::map<int, std::string> * mAddr() { return & m; }. I do not touch preferable good-style scope or name for constant in this question. Let us leave these matters for another question. [END_EDIT]
I want to know answers for all the different cases, so let us assume that T is one of the following:
typedef int T; // 1
typedef long double T; // 2
typedef std::array<char, 1> T; // 3
typedef std::array<long, 1000> T; // 4
typedef std::string T; // 5
typedef QString T; // 6
class T {
// unspecified amount of code
}; // 7
// Something special
// not mentioned above? // 8
I believe that there is no big semantic (I do not discuss good naming or scope style here) difference between the 3 possible scopes:
// header.hpp
extern const T tv;
T tf(); // Global
namespace Nm {
extern const T tv;
T tf(); // Namespace
}
struct Cl {
static const T tv;
static T tf(); // Class
};
But if choosing better way from alternatives below depends on the difference between above declaration scopes, please point it out.
Consider also the case when function call is used in constant definition, e.g. <some value>==f();. How would calling a function in constant initialization influence choosing between alternatives?
Let us consider T with constexpr constructor first.
Obvious alternatives are:
// header.hpp
namespace Ns {
constexpr T A = <some value>;
constexpr T B() { return <some value>; }
inline const T & C() { static constexpr T t = <some value>; return t; }
const T & D();
}
// source.cpp
const T & Ns::D() { static constexpr T t = <some value>; return t; }
I believe that A and B are most suitable for small T (such that having multiple instances or copying it at runtime is not a problem), e.g. 1-3, sometimes 7. C and D are better if T is large, e.g. 4, sometimes 7.
T without constexpr constructor. Alternatives:
// header.hpp
namespace Ns {
extern const T a;
inline T b() { return <some value>; }
inline const T & c() { static const T t = <some value>; return t; }
const T & d();
}
// source.cpp
extern const T Ns::a = <some value>;
const T & Ns::d() { static const T t = <some value>; return t; }
I would not normally use a because of static initialization order fiasco. As far as I know, b, c and d are perfectly safe, even thread-safe since C++11. b does not seem to be a good choice unless T has a very cheap constructor, which is uncommon for non-constexpr constructors. I can name one advantage of c over d - no function call (run-time performance); one advantage of d over c - less recompiling when constant's value is changed (these advantages also apply to C and D). I am sure that I missed a lot of reasoning here. Provide other considerations in answers please.
If you want to modify / test the above code, you can use my test files (just header.hpp, source.cpp with compilable versions of above code fragments and main.cpp that prints constants from header.hpp): https://docs.google.com/uc?export=download&id=0B0F-aqLyFk_PVUtSRnZWWnd4Tjg
I believe that there is no big difference between the following declaration locations:
This is wrong in a lot of ways.
The first declaration pollutes the global namespace; you have taken the name "tv" from ever being used again without the possibility of misunderstandings. This can cause shadowing warnings, it can cause linker errors, it can cause all sorts of confusion to anyone who uses your header. It can also cause problems to someone who doesn't use your header, by causing a collision with someone else who also happens to use your variable name as a global.
Such an approach is not recommended in modern C++, but is ubiquitous in C, and therefore leads to much use of the static keyword for "global" variables in a .c file (file scope).
The second declares pollutes a namespace; this is much less of an issue, as namespaces are freely renamable and can be made at no cost. As long as two projects use their own, relatively specific namespace, no collisions will occur. In the case where such collisions do occur, the namespaces for each can be renamed to avoid any issues.
This is more modern, C++03 style, and C++11 expands this tactic considerably with renaming of templates.
The third approach is a struct, not a class; they have differences, especially if you want to maintain compatibility with C. The benefits of a class scope compound on the namespace scope; not only can you easily encapsulate multiple things and use a specific name, you can also increase encapsulation via methods and information hiding, greatly expanding how useful your code is. This is mostly the benefit of classes, irrespective of scoping benefits.
You should almost certainly not use the first one, unless your functions and variables are very broad and STL/STD like, or your program is very small and not likely to be embedded or reused.
Let's now look at your cases.
The size of the constructor, if it returns a constant expression, is unimportant; all of the code ought to be executable at compile time. This means the complexity is not meaningful; it will always compile to a single, constant, return value. You should almost certainly never use C or D; all that does is make the optimizations of constexpr not work. I would use whichever of A and B looks more elegant, probably a simple assignment would be A, and a complex constant expression would be B.
None of these are necessarily thread safe; the content of the constructor would determine both thread and exception safety, and it is quite easy to make any of these statements not thread safe. In fact, A is most likely to be thread safe; as long as the object is not accessed until main is called, it should be fully formed; the same cannot be said of any of your other examples. As for your analysis of B, in my experience, most constructors (especially exception safe ones) are cheap as they avoid allocation. In such cases, there's unlikely to be much difference between any of your cases.
I would highly recommend you stop attempting micro-optimizations like this and perhaps get a more solid understanding of C++ idioms. Most of the things you are trying to do here are unlikely to result in any increase in performance.
You didn't mention an important option:
namespace
{
const T t = .....;
};
Now there are no name collision issues.
This isn't appropriate if T is something you only want to construct once. But having a large "global" object, const or not, is something you really want to avoid. It breaks encapsulation, and also introduces the static initialization order fiasco into your code.
I've never had the need for a large extern const object. If I need a large hardcoded lookup table for example, then I write a function (perhaps as a class member) that looks up the table; and the table is local to the unit with the implementation of that function.
In my code that seems to call for a large non-const global object, I actually have a function,
namespace MyStuff
{
T &get_global_T();
}
which constructs the object on first use. (Actually, the object itself is hidden in one unit, and T is a helper class that specifies an interface; so I can mess around with the object's details and not disturb any code that is using it).
1
In case A there is a difference between global or namespace scope (internal linkage) and class scope (external linkage). So
// header.hpp
constexpr T A = <some value>; // internal linkage
namespace Nm { constexpr T A = <some value>; } // internal linkage
class Cl { public: static constexpr T A = <some value>; }; // not enough!
Consider the following usage:
// user.cpp
std::cout << A << Nm::A << Cl::A; // ok
std::cout << &A << &Nm::A; // ok
std::cout << &Cl::A; // linker error: undefined reference to `Cl::A'
Placing Cl::A definition in source.cpp (in addition to the above Cl::A declaration) eliminates this error:
// source.cpp
constexpr T Cl::A;
External linkage means that there would always be only one instance of Cl::A. So Cl::A seems to be a very good candidate for large T. However: can we be sure that static initialization order fiasco would not present itself in this case? I believe that the answer is yes, because Cl::A is constructed at compile-time.
I have tested A, B, a alternatives with g++ 4.8.2 and 4.9.0, clang++ 3.4 on GNU/Linux platform. The results for three translation units:
A in class scope with definition in source.cpp was both immune to fiasco and had the same address in all translation units even at compile-time.
A in namespace or global scope had 3 different addresses both for large array and constexpr const char * A = "A"; (because of internal linkage).
B (std::array<long double, 100>) in any scope had 2 different addresses (address was the same in 2 translation units); additionally all 3 B addresses suggested some different memory location (they were much bigger than other addresses) - I suspect that array was copied in memory at runtime.
a when used with constexpr types T, e.g. int, const char *, std::array, AND initialized with constexpr expression in source.cpp, was as good as A: immune to fiasco and had the same address in all translation units. If constant of constexpr type T is initialized with non-constexpr, e.g. std::time(nullptr), and used before initialization, it would contain default value (for example, 0 for int). It means that constant's value can depend on static initialization order in this case. So, do not initialize a with non-constexpr value!
The bottom line
prefer A in class scope for any constexpr constant in most cases because it combines perfect safety, simplicity, memory saving and performance.
a (initialized with constexpr value in source.cpp!) should be used if namespace scope is preferable or it is desirable to avoid initialization in header.hpp (in order to reduce dependencies and compilation time). a has one disadvantage compared to A: it can be used in compile-time expressions only in source.cpp and only after initialization.
B should be used for small T in some cases: when namespace scope is preferable or template compile-time constant is needed (pi for example). Also B can be used when constant's value is rarely used or used only in exceptional situations, e.g. error messages.
Other alternatives should almost never be used as they would rarely suit better than all 3 before-mentioned ways.
A in namespace scope should not be used because it can potentially lead to N instances of constant, hence consume sizeof(T) * N bytes of memory and cause cache misses. Here N equals to the number of translation units that include header.hpp. As noted in this proposal, A in namespace scope can violate ODR if used in inline function.
C could be used for big T (B is usually better for small T) in 2 rare scenarios: when function call is preferable; when namespace scope AND initializing in header is preferable.
D could be used when function call AND initializing in source file is preferable.
The only shortcoming of C compared to A and B - its return value can not be used in compile-time expression. D suffers from the same shortcoming and another one: function call run-time performance penalty (because it can not be inlined).
2
Avoid using non-constexpr a because of static initialization order fiasco. Consider a only in case of sure bottleneck. Otherwise, safety is more important than small performance gain. b, c and d are much safer. However c and d have 2 safety requirements:
for (auto f : {all c and d-like functions}) {
T constructor must not call f because if the initialization of static local variable recursively enters the block in which the variable is being initialized, the behavior is undefined. This is not difficult to ensure.
For each class X such that X::~X calls f and there is a statically initialized X object: X::X must call f. The reason is that otherwise static const T from f could be constructed after and therefore destructed before global X object; then X::~X would cause UB. This requirement is much more difficult to guarantee than the previous one. So it almost prohibits global or static local variables with complicated destructors that use global constants. If destructor of statically initialized variable is not complicated, e.g. uses f() for logging purposes, then placing f(); in the corresponding constructor ensures safety.
}
Note: these 2 requirements do not apply to C and D:
the recursive call to f would not compile;
static constexpr T constants in C and D are constructed at compile time - before any non-trivial variable is constructed, so they are destructed after all non-trivial variables' destruction (destructors are called in reverse order).
Note 2: C++ FAQ suggests a different implementation of c and d, which does not impose the second safety requirement. However in this case static constant is never destructed, which can interfere with memory leak detection, e.g. Valgrind diagnostic. Memory leaks, however benign, should be avoided. So these modified versions of c and d should be used only in exceptional situations.
One more alternative to consider here is a constant with internal linkage:
// header.hpp
namespace Ns { namespace { const T a1 = <some value>; } }
This approach has the same big downside as A in namespace scope: internal linkage can create as many copies of a1 as the number of translation units that include header.hpp. It can also violate ODR in the same way as A. However, since other options for non-constexpr are not as good as for constexpr constants, this alternative actually could have some rare use. BUT: this "solution" is still prone to static initialization order fiasco in case when a1 is used in public function which in turn is used for initialization of a global object. So introducing internal linkage does not solve the problem - just hides it, makes it less likely, probably more difficult to locate and fix.
The bottom line
c provides the best performance and saves memory because it facilitates reusing exactly one T instance and can be inlined, so it should be used in most cases.
d is as good as c for saving memory but is worse for performance as it would never be inlined. However d can be used to reduce compilation time.
consider b for small types or for rarely used constants (in rarely-used-constant case its definition can be moved to source.cpp to avoid recompilation on change). Also b is the only solution if safety requirements for c and d can not be satisfied. b is definitely not good for large T if constant is used often, because the constant has to be constructed each time b is called.
Note: there is another compile-time issue of inline functions and variables initialized in header.hpp. If constant's definition depends on another constant declared in a different header bad.h, and header bad.h should not be included in header.hpp, then D, d, a and modified b (with definition moved to source.cpp) are the only alternatives.
Related
Consider code like the following, where the literal some_magic_int (e.g. 3) is given a name just to make a bit clearer what constant it represents:
void f() {
static constexpr int this_variable{some_magic_int};
do_something_with(this_variable);
}
int main() {
// ...
f();
// ...
}
I'm pretty sure constexpr has to be here: some_magic_int is literal, so it never changes, and I'm giving it a name just for clarity, not to give a mean to change it, so it should be at least const; then why not constexpr to have it at compile-time?
But what about static? Is it just unnecessary? Or is it detrimental? If so, why? And also, does it have any observable effect, when paired with constexpr in the declaration of a local variable?
As regards the question to which this is marked as duplicate of, it is about static constexpr int x [] = {}, and not static constexpr int x {}. This highlights at least one difference between that case (attributes applying to x pointer vs attributes applied to *x pointee) and my case (there's no pointer).
Furthermore, once I add constexpr to the specifier of a local variable (where it makes sense, e.g. to a int), I'm saying that variable is compile-time known. Why in the world doesn't that imply that no run-time entity is needed whatsoever?
The standard doesn’t actually ever talk about compile-time anything except to say that types are checked and templates are instantiated before execution. That means that this program must be diagnosed (not “rejected”!) even though the non-constant array length and template argument are never “used” and might plausibly be ignored by an interpreter:
template<int> void f() {}
int main(int argc,char **argv) {
if(false) {
int buf[argc]; // accepted by a common extension
f<argc>();
}
}
Beyond that, the semantics are that every evaluation is part of the ordinary execution of the program and constant folding is just an as-if optimization like any other. (After all, we can optimize argc*2*3*4 even though it contains no non-literal subexpression that could be a constant expression.) For constant expressions, this is largely unobservable because constant evaluation can’t have side effects (which also avoids interactions among constant-initialized non-block variables). It can, however, make a difference via the address of the local variable:
bool introspect(const int *p=nullptr) {
constexpr int x=0;
return p ? p==&x : introspect(&x); // always false
}
That the compiler must make such variables occupy memory if their address escapes is much of the content of the answers to the previously marked duplicate. It therefore makes sense to prefer static except perhaps when the object is large and its address doesn’t matter (e.g., for use as a template argument or via recursion).
If an object is declared const, its value is guaranteed to be available only at runtime, but if it's declared constexpr, the value is guaranteed to be available both during compilation and at runtime. So if I have an object whose value is available during compilation, are there any situations where I should not declare it constexpr?
const int magicValue = 42; // Does this ever make sense
// (using const instead of constexpr)?
For functions, if a function can return a value computed during compilation when passed arguments with values available during compilation, would it ever make sense to not declare the function constexpr?
struct Point { int x; int y; };
Point midPoint(Point p1, Point p2) // Does this ever make
{ // sense (not declaring
return { (p1.x + p2.x) / 2 , (p1.y + p2.y) / 2 }; // the function
} // constexpr)?
The only case I can conceive of is when you don't want to commit to the function being able to compute a compile-time constant when called with known-at-compile-time arguments, e.g., if you want to preserve the flexibility to change midPoint's implementation without changing its interface (thus potentially breaking callers). For example, you might want to preserve the flexibility to add non-constexpr side-effects to midPoint, e.g., IO.
For variables, I don't see any reason not to use constexpr when you can. But it's not always possible to do so, e.g. when the initializer of a variable is computed by a virtual function e.g.
Adding constexpr to a function is an interface change: you are expressing the fact that you can use it to initialize constexpr variables. This imposes constraints on the implementation of your function, such as no calling of virtual functions, no dynamic memory allocations and no lambda functions as function objects.
Note that the resolution to LWG issue 2013 does not allow implementers of the Standard Library the freedom to add constexpr to library functions. One of the reasons is that declaring a function constexpr can inhibit certain debugging implementations that do dynamic allocations (notably iterator checking). This means that future expansions of constexpr to the Standard Library need to be separate proposals. This is in contrast to noexcept, where library writers have more freedom.
You can change a const:
int const x = 1;
*const_cast<int *>(&x) = 5;
You cannot do the same with constexpr, which allows the compiler to know without a doubt that the expression is available at compile time, and thus optimizations are possible.
From everything I am reading and testing, there is no way (without a preprocessor macro) to define a constant in a shared header and ensure that each TU is not creating its own storage for that constant.
I can do this:
const int maxtt=888888;
Which is the same exactly as:
static const int maxtt=888888;
And if this header is shared, it will work but each TU gets its own copy of maxtt. I could also do this, to prevent that:
extern const int maxtt;
But then I cannot define maxtt here; that must be done in a CPP to avoid linker error.
Is my understanding correct?
Since the variable is constant, the fact that each TU gets its own copy is usually irrelevant.
In C++, constants at namespace scope are implicitly static for this reason. Often this allows for better code than if you only had a single instance with external linkage, since (if the variable is actually a constant expression) the constant can often be folded right into the usage site and doesn't need to be stored at all.
So unless you really need to take the address of the constant, or something like that, you should stick with the static version. (And as you already observed, you can force external linkage by adding extern.) Another reason may be that you're initializing dynamically and only want one call to the initializer:
// header:
extern int const n;
// one implementation:
int const n = init_function_with_side_effects();
The static construction (int const n = init(); in the header) would cause the function to be called once in every TU.
You write,
“From everything I am reading and testing, there is no way (without a preprocessor macro) to define a constant in a shared header and ensure that each TU is not creating its own storage for that constant.”
Happily that’s incorrect.
For a small integral value you can always just use an enum. The trade-off is that you can’t pass the address of an enum value, because it has no address. It’s pure value.
However, saving space for an integral value is a pretty meaningless thing to do, since it’s so small.
So, let’s consider a biggie thingy,
struct BiggyThingy
{
unsigned char zeroes[1000000];
BiggyThingy(): zeroes() {}
};
Now how can we declare a BiggyThingy constant in a header file and ensure a single one overall for the whole program?
Using an inline function.
Well the simplest is this:
inline BiggyThingy const& getBiggyThingy()
{
static BiggyThingy const theThingy;
return theThingy;
}
static BiggyThingy const& biggyThingy = getBiggyThingy();
If you don’t want a reference taking up space (like a pointer) in each translation unit, then just use the function without the notation-simplifying reference.
Using the template constant trick.
Here is another way to provide the constant, leveraging a special rule for templates instead:
template< class Dummy >
class BiggyThingyConstant_
{
public:
static BiggyThingy const value;
};
template< class Dummy >
BiggyThingy const BiggyThingyConstant_<Dummy>::value;
typedef BiggyThingyConstant_<void> BiggyThingyConstant;
which can be accessed like
foo( BiggyThingyConstant::value )
Or if you want nicer notation you can add a reference per translation unit, as for the inline function solution.
Disclaimer:
Code untouched by compiler.
But you get the ideas, I think. ;-)
This code generates a constant in the TU only if you apply any operation that requires the address of the constant.
static int maxtt = 888888;
int * pmaxtt = &maxtt; //address of constant requested.
This may work as well and avoids the linker problem (though it'll store maxtt in each TU if the address is requested):
constexpr int maxtt = 888888;
Avoid the extern construction as it can't be optimized.
If you're so worried about storage, use an enumeration:
enum { maxtt = 888888 };
Enumerators are scalar rvalues and hence do not require storage. It is illegal to say &maxtt.
Indeed, your understanding of the semantics are correct.
In practice, each translation unit might not get a copy of the storage for the integer. One reason is that the compiler might implement the value as a literal wherever it is referenced. The linker might also be smart enough to discard the storage if it finds it isn't referenced.
The compiler might not be free to use a literal for your constant. You might take a reference to that integer, or get a pointer to it. In that case, you need the storage -- and you might even need the cross-compiland uniqueness. If you take the address of your const symbol in each compilation unit, you might find that its different since each object will get a unique, static copy.
You might have a similar problem if you use an enum; your const int has storage, and you can take the address of that storage. You can't take the address of an enumerand until you store it someplace.
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
return A::B::b;
}
The above code compiles. However if you go by Effective C++ book by Scott Myers(pg 14);
We need a definition for a in addition to the declaration.
Can anyone explain why this is an exception?
C++ compilers allow static const integers (and integers only) to have their value specified at the location they are declared. This is because the variable is essentially not needed, and lives only in the code (it is typically compiled out).
Other variable types (such as static const char*) cannot typically be defined where they are declared, and require a separate definition.
For a tiny bit more explanation, realize that accessing a global variable typically requires making an address reference in the lower-level code. But your global variable is an integer whose size is this typically around the size of an address, and the compiler realizes it will never change, so why bother adding the pointer abstraction?
By really pedantic rules, yes, your code needs a definition for that static integer.
But by practical rules, and what all compilers implement because that's how the rules of C++03 are intended - no, you don't need a definition.
The rules for such static constant integers are intended to allow you to omit the definition if the integer is used only in such situations where a value is immediately read, and if the static member can be used in constant expressions.
In your return statement, the value of the member is immediately read, so you can omit the definition of the static constant integer member if that's the only use of it. The following situation needs a definition, however:
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
int *p = &A::B::b;
}
No value is read here - but instead the address of it is taken. Therefore, the intent of the C++03 Standard is that you have to provide a definition for the member like the following in some implementation file.
const int A::B::b;
Note that the actual rules appearing in the C++03 Standard says that a definition is not required only where the variable is used where a constant expression is required. That rule, however, if strictly applied, is too strict. It would only allow you to omit a definition for situation like array-dimensions - but would require a definition in cases like a return statement. The corresponding defect report is here.
The wording of C++0x has been updated to include that defect report resolution, and to allow your code as written.
However, if you try the ternary operand without "defining" static consts, you get a linker error in GCC 4x:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795
So, although constructs like int k = A::CONSTVAL; are illegal in the current standard, they are supported. But the ternary operand is not. Some operators are more equal than others, if you get my drift :)
So much for "lax" rules. I suggest you write code conforming to the standard if you do not want surprises.
In general, most (and recent) C++ compilers allow static const ints
You just lucky, perhaps not. Try older compiler, such as gcc 2.0 and it will vehemently punish you with-less-than-pretty error message.
Note this question was originally posted in 2009, before C++11 was ratified and before the meaning of the auto keyword was drastically changed. The answers provided pertain only to the C++03 meaning of auto -- that being a storage class specified -- and not the C++11 meaning of auto -- that being automatic type deduction. If you are looking for advice about when to use the C++11 auto, this question is not relevant to that question.
For the longest time I thought there was no reason to use the static keyword in C, because variables declared outside of block-scope were implicitly global. Then I discovered that declaring a variable as static within block-scope would give it permanent duration, and declaring it outside of block-scope (in program-scope) would give it file-scope (can only be accessed in that compilation unit).
So this leaves me with only one keyword that I (maybe) don't yet fully understand: The auto keyword. Is there some other meaning to it other than 'local variable?' Anything it does that isn't implicitly done for you wherever you may want to use it? How does an auto variable behave in program scope? What of a static auto variable in file-scope? Does this keyword have any purpose other than just existing for completeness?
In C++11, auto has new meaning: it allows you to automatically deduce the type of a variable.
Why is that ever useful? Let's consider a basic example:
std::list<int> a;
// fill in a
for (auto it = a.begin(); it != a.end(); ++it) {
// Do stuff here
}
The auto there creates an iterator of type std::list<int>::iterator.
This can make some seriously complex code much easier to read.
Another example:
int x, y;
auto f = [&]{ x += y; };
f();
f();
There, the auto deduced the type required to store a lambda expression in a variable.
Wikipedia has good coverage on the subject.
auto is a storage class specifier, static, register and extern too. You can only use one of these four in a declaration.
Local variables (without static) have automatic storage duration, which means they live from the start of their definition until the end of their block. Putting auto in front of them is redundant since that is the default anyway.
I don't know of any reason to use it in C++. In old C versions that have the implicit int rule, you could use it to declare a variable, like in:
int main(void) { auto i = 1; }
To make it valid syntax or disambiguate from an assignment expression in case i is in scope. But this doesn't work in C++ anyway (you have to specify a type). Funny enough, the C++ Standard writes:
An object declared without a storage-class-specifier at block scope or declared as a function parameter has automatic storage duration by default. [Note: hence, the auto specifier is almost always redundant and not often used; one use of auto is to distinguish a declaration-statement from an expression-statement (6.8) explicitly. — end note]
which refers to the following scenario, which could be either a cast of a to int or the declaration of a variable a of type int having redundant parentheses around a. It is always taken to be a declaration, so auto wouldn't add anything useful here, but would for the human, instead. But then again, the human would be better off removing the redundant parentheses around a, I would say:
int(a);
With the new meaning of auto arriving with C++0x, I would discourage using it with C++03's meaning in code.
The auto keyword has no purpose at the moment. You're exactly right that it just restates the default storage class of a local variable, the really useful alternative being static.
It has a brand new meaning in C++0x. That gives you some idea of just how useless it was!
GCC has a special use of auto for nested functions - see here.
If you have nested function that you want to call before its definition, you need to declare it with auto.
"auto" supposedly tells the compiler to decide for itself where to put the variable (memory or register). Its analog is "register", which supposedly tells the compiler to try to keep it in a register. Modern compilers ignore both, so you should too.
I use this keyword to explicitly document when it is critical for function, that the variable be placed on the stack, for stack-based processors. This function can be required when modifying the stack prior to returning from a function (or interrupt service routine).
In this case I declare:
auto unsigned int auiStack[1]; //variable must be on stack
And then I access outside the variable:
#define OFFSET_TO_RETURN_ADDRESS 8 //depends on compiler operation and current automatics
auiStack[OFFSET_TO_RETURN_ADDRESS] = alternate_return_address;
So the auto keyword helps document the intent.
According to Stroustrup, in "The C Programming Language" (4th Edition, covering C 11), the use of 'auto' has the following major reasons (section 2.2.2) (Stroustrup words are quoted):
1)
The definition is in a large scope where we want to make the type
clearly visible to readers of our code.
With 'auto' and its necessary initializer we can know the variable's type in a glance!
2)
We want to be explicit about variable's range or precision (e.g., double rather than float)
In my opinion a case that fits here, is something like this:
double square(double d)
{
return d*d;
}
int square(int d)
{
return d*d;
}
auto a1 = square(3);
cout << a1 << endl;
a1 = square(3.3);
cout << a1 << endl;
3)
Using 'auto' we avoid redundancy and writing long type names.
Imagine some long type name from a templatized iterator:
(code from section 6.3.6.1)
template<class T> void f1(vector<T>& arg) {
for (typename vector<T>::iterator p = arg.begin(); p != arg.end(); p)
*p = 7;
for (auto p = arg.begin(); p != arg.end(); p)
*p = 7;
}
In old compiler, auto was one way to declare a local variable at all. You can't declare local variables in old compilers like Turbo C without the auto keyword or some such.
The new meaning of the auto keyword in C++0x is described very nicely by Microsoft's Stephan T. Lavavej in a freely viewable/downloadable video lecture on STL found at MSDN's Channel 9 site here.
The lecture is worth viewing in its entirety, but the part about the auto keyword is at about the 29th minute mark (approximately).
Is there some other meaning to 'auto' other than 'local variable?'
Not in C++03.
Anything it does that isn't implicitly done for you wherever you may want to use it?
Nothing whatsoever, in C++03.
How does an auto variable behave in program scope? What of a static auto variable in file-scope?
Keyword not allowed outside of a function/method body.
Does this keyword have any purpose [in C++03] other than just existing for completeness?
Surprisingly, yes. C++ design criteria included a high degree of backward compatibility with C. C had this keyword and there was no real reason to ban it or redefine its meaning in C++. So, the purpose was one less incompatibility with C.
Does this keyword have any purpose in C other than just existing for completeness?
I learned one only recently: ease of porting of ancient programs from B. C evolved from a language called B whose syntax was quite similar to that of C. However, B had no types whatsoever. The only way to declare a variable in B was to specify its storage type (auto or extern). Like this:
auto i;
This syntax still works in C and is equivalent to
int i;
because in C, the storage class defaults to auto, and the type defaults to int. I guess that every single program that originated in B and was ported to C was literally full of auto variables at that time.
C++03 no longer allows the C style implicit int, but it preserved the no-longer-exactly-useful auto keyword because unlike the implicit int, it wasn't known to cause any trouble in the syntax of C.