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.
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).
Suppose I'm using some C library which has a function:
int foo(char* str);
and I know for a fact that foo() does not modify the memory pointed to by str. It's just poorly written and doesn't bother to declare str being constant.
Now, in my C++ code, I currently have:
extern "C" int foo(char* str);
and I use it like so:
foo(const_cast<char*>("Hello world"));
My question: Is it safe - in principle, from a language-lawyering perspective, and in practice - for me to write:
extern "C" int foo(const char* str);
and skip the const_cast'ing?
If it is not safe, please explain why.
Note: I am specifically interested in the case of C++98 code (yes, woe is me), so if you're assuming a later version of the language standard, please say so.
Is it safe for me to write: and skip the const_cast'ing?
No.
If it is not safe, please explain why.
-- From language side:
After reading the dcl.link I think exactly how the interoperability works between C and C++ is not exactly specified, with many "no diagnostic required" cases. The most important part is:
Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function.
Because they refer to the same function, I believe a sane assumption would be that the declaration of a identifier with C language linkage on C++ side has to be compatible with the declaration of that symbol on C side. In C++ there is no concept of "compatible types", in C++ two declarations have to be identical (after transformations), making the restriction actually more strict.
From C++ side, we read c++draft basic#link-11:
After all adjustments of types (during which typedefs are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, [...]
Because the declaration int foo(const char *str) with C language linkage in a C++ translation unit is not identical to the declaration int foo(char *str) declared in C translation unit (thus it has C language linkage), the behavior is undefined (with famous "no diagnostic required").
From C side (I think this is not even needed - the C++ side is enough to make the program have undefined behavior. anyway), the most important part would be C99 6.7.5.3p15:
For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types [...]
Because from C99 6.7.5.1p2:
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
and C99 6.7.3p9:
For two qualified types to be compatible, both shall have the identically qualified version of a compatible type [...]
So because char is not compatible with const char, thus const char * is not compatible with char *, thus int foo(const char *) is not compatible with int foo(char*). Calling such a function (C99 6.5.2.2p9) would be undefined behavior (you may see also C99 J.2)
-- From practical side:
I do not believe will be able to find a compiler+architecture combination where one translation unit sees int foo(const char *) and the other translation unit defines a function int foo(char *) { /* some stuff */ } and it would "not work".
Theoretically, an insane implementation may use a different register to pass a const char* argument and a different one to pass a char* argument, which I hope would be well documented in that insane architecture ABI and compiler. If that's so, wrong registers will be used for parameters, it will "not work".
Still, using a simple wrapper costs nothing:
static inline int foo2(const char *var) {
return foo(static_cast<char*>(var));
}
I think the base answer is:
Yes, you can cast off const even if the referenced object is itself const such as a string literal in the example.
Undefined behaviour is only specified to arise in the event of an attempt to modify the const object not as a result of the cast.
Those rules and their reason to exist is 'old'. I'm sure they predate C++98.
Contrast it with volatile where any attempt to access a volatile object through a non-volatile reference is undefined behaviour. I can only read 'access' as read and/or write here.
I won't repeat the other suggestions but here is the most paranoid solution.
It's paranoid not because the C++ semantics aren't clear. They are clear. At least if you accept something being undefined behaviour is clear!
But you've described it as 'poorly written' and you want to put some sandbags round it!
The paranoid solution relies on the fact that if you are passing a constant object it will be constant for the whole execution (if the program doesn't risk UB).
So make a single copy of "hello world" lower in the call-stack or even initialised as a file scope object. You can declare it static in a function and it will (with minimal overhead) only be constructed once.
This recovers almost all of the benefits of string literal. The lower down the call stack including file-scope (global you put it the better.
I don't know how long the lifetime of the pointed-to object passed to foo() needs to be.
So it needs to be at least low enough in the chain to satisfy that condition.
NB: C++98 has std::string but it won't quite do here because you're still forbidden for modifying the result of c_str().
Here the semantics are defined.
#include <cstring>
#include <iostream>
class pseudo_const{
public:
pseudo_const(const char*const cstr): str(NULL){
const size_t sz=strlen(cstr)+1;
str=new char[sz];
memcpy(str,cstr,sz);
}
//Returns a pointer to a life-time permanent copy of
//the string passed to the constructor.
//Modifying the string through this value will be reflected in all
// subsequent calls.
char* get_constlike() const {
return str;
}
~pseudo_const(){
delete [] str;
}
private:
char* str;
};
const pseudo_const str("hello world");
int main() {
std::cout << str.get_constlike() << std::endl;
return 0;
}
I tend to use the words define, declare and assign interchangeably but this seems to cause offense to some people. Is this justified? Should I only use the word declare for the first time I assign to a variable? Or is there more to it than that?
A definition is where a value or function is described, i.e. the compiler or programmer is told precisely what it is, e.g.
int foo()
{
return 1;
}
int var; // or, e.g. int var = 5; but this is clearer.
A declaration tells the compiler, or programmer that the function or variable exists. e.g.
int foo();
extern int var;
An assignment is when a variable has its value set, usually with the = operator. e.g.
a = b;
a = foo();
Define and declare are similar but assign is very different.
Here I am declaring (or defining) a variable:
int x;
Here I am assigning a value to that variable:
x = 0;
Here I am doing both in one statement:
int x = 0;
Note
Not all languages support declaration and assignment in one statement:
T-SQL
declare x int;
set x = 0;
Some languages require that you assign a value to a variable upon declaration. This requirement allows the compiler or interpreter of the language to infer a type for the variable:
Python
x = 0
It is important to use the correct terminology, otherwise people will not know what you are talking about, or incorrectly assume that you don't know what you are talking about.
These terms often have precise meanings in the standards for various languages. When that is the case they should not be conflated.
In c for instance:
a function may be defined only once (when you say what it does), but it may also be declared before that (when you say what arguments it takes and what type it returns).
likewise a variable is declared when you say what type it is, and this happens only once for each scope. But you may assign a value repeatedly. (Some languages also differentiate between initialization (giving a variable a value at declaration time) and assignment (changing the value later).)
General Role:
Definition = declaration + reserved space.
Definition, declaration, and assignment have two cases:
for Variables.
for Functions.
For Variables:
-- Definition:
To tell the compiler to reserve memory for the variable.
int x;
-- Declaration:
To tell the compiler that the variable defined in somewhere else.
extern int x;
-- Assignment:
To tell the compiler to put the value in the variable.
x = 0;
For Functions:
-- Definition:
int functionDef(int x){
int x;
...
...
...
return x;
}
-- Declaration:
It is just the prototype of the function.
int functionDef(int x);
The differences can seem subtle, but they are important. Not every language makes the same distinctions, but in C++ a variable declaration makes the type and name of the variable known to the compiler
int i;
A variable definition allocates storage and specifies an initial value for the variable.
i = 1;
You can combine a variable declaration and definition into one statement, as is commonly done.
int x = 1;
Declaring a variable inside a function will also set aside memory for the variable, so the following code implicitly defines variable a as a part of its declaration.
int main()
{
int a;
return 0;
}
Since variable a is automatically defined by the compiler, it will contain whatever value was in the memory location that was allocated for it. This is why it is not safe to use automatic variables until you've explicitly assigned a known value to them.
An assignment takes place any time you change the value of a variable in your program.
x = 2;
x++;
x += 4;
A function declaration, similar to the variable declaration, makes the function signature known to the compiler. This allows you to call a function in your source code before it is defined without causing a compiler error.
int doSomething(float x);
A function definition specifies the return type, name, parameter list, and instructions for a function. The first three of these elements must match the function declaration. A function must only be defined once in a given program.
int doSomething(float x)
{
if( x < 0 )
{
x = -x;
}
return static_cast<int>(x);
}
You can combine the function decalartion and definition into one, but you must do so before the function is called anywhere in your program.
It might depend on the language, as has been said. I think it really depends on whether the words are used for things like classes. For most of the data types discussed here, the question might not have much relevance. In C++ (see c++ - What is the difference between a definition and a declaration?), a class or struct always has precisely one definition but can be declared zero or more times. A class cannot be declared without a definition. So "declared" might be synonymous with "used".
In most languages, simple types such as integers do not need definitions in the manner that classes do.
The correct answer depends on which language you're talking about. Computer languages often have specific terminology, either because of the language specification or the community grown up around the language. COBOL, back when I used it, had a much different terminology than more mainstream languages (in the sense of languages closer to the mainstream of language development, not mainstream business). Forth developed some strange terminology.
If you know English, you can usually get a good idea as to what a word means from its normal meaning, but never count on it too much. The same is true with specific words across languages or language communities.
I have recently discovered an annoying problem in some large program i am developing; i would like to understand how to fix it in a best way. I cut the code down to the following minimal example.
#include <iostream>
using std::cin;
using std::cout;
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
int main()
{
int choice;
cout << "How much stuff do you want?\n";
cin >> choice;
int stuff = (choice < 20) ? MagicNumbers::SMALL : MagicNumbers::BIG; // PROBLEM!
cout << "You got " << stuff << "\n";
return 0;
}
I get link errors in gcc 4.1.2 when compiling with -O0 or -O1 but everything is OK when compiling with -O2 or -O3. It links well using MS Visual Studio 2005 regardless of optimization options.
test.cpp:(.text+0xab): undefined reference to `MagicNumbers::SMALL'
test.cpp:(.text+0xb3): undefined reference to `MagicNumbers::BIG'
I looked at the intermediate assembly code, and yes, the non-optimized code regarded SMALL and BIG as external int variables, while the optimized one used the actual numbers. Each of the following changes fixes the problem:
Use enum instead of int for constants: enum {SMALL = 10}
Cast the constant (any one) at each usage: (int)MagicNumbers::SMALL or (int)MagicNumbers::BIG or even MagicNumbers::SMALL + 0
Use a macro: #define SMALL 10
Not use the choice operator: if (choice < 20) stuff = MagicNumbers::SMALL; else stuff = MagicNumbers::BIG;
I like the first option best (however, it's not ideal because we actually use uint32_t instead of int for these constants, and enum is synonymous with int). But what i really want to ask is: whose bug is it?
Am i the one to blame for not understanding how static integral constants work?
Should i blame gcc and hope for a fix (or maybe the latest version already has a fix, or maybe there is an obscure command-line argument to make this work)?
Meanwhile, i just compile my code with optimizations, and it's a pain to debug :-O3
This is a known issue. The Standard is to blame or you for not providing a definition of the statics. Depending on your point of view :)
In spite of the conventional advice, I have found that static const int ... invariably gives me more headaches than good old enum { BIG = 100, SMALL = 10 };. And with C++11 providing strongly-typed enums, I now have even less cause to use static const int ....
Static data members don't work like that in C++:
Static data members are not part of
objects of a given class type; they
are separate objects. As a result, the
declaration of a static data member is
not considered a definition. The data
member is declared in class scope, but
definition is performed at file scope.
These static members have external
linkage.
You're only declaring those constants, even though you're initializing them. You still have to define them at namespace scope:
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
const int MagicNumbers::BIG;
const int MagicNumbers::SMALL;
That will get rid of the link errors.
Heh, according to the C++ standard, 9.4.2 (class.static.data):
If a static data member is of const
literal type, its declaration in the
class definition can specify a
brace-or-equal-initializer in which
every initializer-clause that is an
assignment-expression is a constant
expression. A static data member of
literal type can be declared in the
class definition with the constexpr
specifier; if so, its declaration
shall specify a
brace-or-equal-initializer in which
every initializer-clause that is an
assignment-expression is a constant
expression. [ Note: In both these
cases, the member may appear in
constant expressions. —end note ] The
member shall still be defined in a
namespace scope if it is used in the
program and the namespace scope
definition shall not contain an
initializer.
So the declaration is correct, but you still need to have a definition somewhere. I always thought you could skill the definition, but I suppose that isn't standard conforming.
I'm new to C++, but I think that your class declaration only declares that those static members exist, you still need to define them somewhere:
class MagicNumbers
{
public:
static const int BIG;
static const int SMALL;
};
const int MagicNumbers::BIG = 100;
const int MagicNumbers::SMALL = 10;
The higher optimisation levels probably include a level of static analysis thorough enough to determine that BIG and SMALL can be exchanged with their actual values and not to give them any actual storage (the semantics will be the same), so defining these variables in this circumstance would be redundant, hence it links OK.
I'd be hard pressed to assert that it's anyone's bug.
Static const integrals given values at point of declaration are not variables, they're constant expressions. For there to be a variable you still need to define it.
The rules wrt the ternary operator are pretty absurdly complex, probably necessarily so, and actually doesn't really say anything about constant expressions, only rvalues; obviously the compiler thinks they should be variables unless optimization is cranked way up. I think it's free to interpret the expression either way (as a constant expression or as variable).
You still need to allocate space for them somewhere:
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
const int MagicNumbers::BIG;
const int MagicNumbers::SMALL;
Why are your magic numbers in a class?
namespace MagicNumbers {
const int BIG = 100;
const int SMALL = 10;
}
Problem solved without needing to worry about flaws in the C++ standard.
The typical way to define an integer constant to use inside a function is:
const int NumbeOfElements = 10;
the same for using within a class:
class Class {
...
static const int NumberOfElements = 10;
};
It can then be used as a fixed-size array bound which means it is known at compile time.
Long ago compilers didn't support the latter syntax and that's why enums were used:
enum NumberOfElementsEnum { NumberOfElements = 10; }
Now with almost every widely used compiler supporting both the in-function const int and the in-class static const int syntax is there any reason to use the enum for this purpose?
The reason is mainly brevity. First of all, an enum can be anonymous:
class foo {
enum { bar = 1 };
};
This effectively introduces bar as an integral constant. Note that the above is shorter than static const int.
Also, no-one could possibly write &bar if it's an enum member. If you do this:
class foo {
static const int bar = 1;
}
and then the client of your class does this:
printf("%p", &foo::bar);
then he will get a compile-time linker error that foo::bar is not defined (because, well, as an lvalue, it's not). In practice, with the Standard as it currently stands, anywhere bar is used where an integral constant expression is not required (i.e. where it is merely allowed), it requires an out-of-class definition of foo::bar. The places where such an expression is required are: enum initializers, case labels, array size in types (excepting new[]), and template arguments of integral types. Thus, using bar anywhere else technically requires a definition. See C++ Core Language Active Issue 712 for more info - there are no proposed resolutions as of yet.
In practice, most compilers these days are more lenient about this, and will let you get away with most "common sense" uses of static const int variables without requiring a definition. However, the corner cases may differ, however, so many consider it to be better to just use anonymous enum, for which everything is crystal clear, and there's no ambiguity at all.
Defining static constants directly in the class definition is a later addition to C++ and many still stick to the older workaround of using an enum for that. There might even be a few older compilers still in use which don't support static constants directly defined in class definitions.
Use of enum have one advantage. An enum type is a type, so if you define, for example:
enum EnumType { EnumValue1 = 10, EnumValue2 = 20 ... };
and you have a function like:
void Function1(EnumType Value)
the compiler checks that you are passing a member of the enum EnumType to the function, so only valid values for parameter Value would be EnumValue1 and EnumValue2. If you use constants and change the function to
void Function1(int Value)
the compiler checks that you are passing an int (any int, a constant, variable or literal) to the function.
Enum types are good for grouping related const-values. For only one const value, I do not see any advantage.
In your case, I'd use a constant as well. However, there are other cases where I might be adding other, related constants. Like this:
const int TextFile = 1; // XXX Maybe add other constants for binary files etc.?
In such cases, I use an enum right away with a single value, like this:
enum FileType {
TextFile = 1
// XXX Maybe add other values for binary files etc.?
}
The reason is that the compiler can then issue warnings when I'm using the constant value in switch expressions, as in:
FileType type;
// ...
switch ( type ) {
case TextFile:
// ...
}
In case I decide to add another constant value which is related to the existing value (a different type of file, in this example), virtually all compilers will issue a warning since the new value is not handled in the switch statement.
If I had used 'int' and constants instead, the compiler wouldn't have a chance to issue warnings.
The only reason for using the "enum hack" is that old compilers do not support in-class const definitions, as you say in your question. So, unless you suspect that your code will be ported to an old compiler, you should use const where const is due.
I think that there's no reason to use an enum, and that it's actually better to use a static const int for this purpose, since an enum has its own type (even if implicitly convertible to an integer).
There is a difference between those two. Enums don't have an adress as far as I know. static const ints do though. So if someone takes the adress of the const static int, casts away the const, he can modify the value (although the compiler might ignore the change because he thinks it's const). This is of course pure evil and you should not do it - but the compiler can't prevent it. This can't happen with enums.
And of course - if you (for some reason) need the adress of that const, you need the static const int.
In short - enum is an rvalue while const static int is an lvalue. See http://www.embedded.com/story/OEG20011129S0065 for more details.
Well, the portability is a good reason for using enum. It is great, because you don't have to worry whether your compiler supports "static const int S = 10" or not...
Also, as far as I remember, static variable must be defined somewhere, as well as declared, and the enum value must be declared only.
bottom line - use const.
more details:
I'm not a c++ expert, but this seems a more general design question.
If it's not a must, and you think there's a very low/non-existent probability that the enum will grow to have more then one value, then use a regular const.
even if you are wrong and at some point in the future there will be more values, making an enum the right choice - a simple refactoring and you change you const to enum.