I am working on some code where there is a simple enum in a class. A different piece of code has a pointer to that class and is accessing a value of the enum through the arrow pointer.
How on earth is the class able to access MY_VALUE1 this way?
I though it would only allow access via MyClass::MY_VALUE1 or MyClass::MyEnum::MY_VALUE1.
class MyClass {
public:
enum MyEnum{
MY_VALUE0 = 0,
MY_VALUE1 = 1
};
//getters, setters as appropriate
};
//Other class
MyClass* myClass = new MyClass();
//Compiles without C++11
if(getRandomEnum() == myClass->MY_VALUE1)
{
//Do Stuff
}
The -> operator is (mostly) an abbreviation for dereference (*) and selection (.). In other words, a->b is the same as (*(a)).b. (§5.2.5/2; See notes below).
The . syntax is class member access, as defined by §5.2.5 [expr.ref]; the identifier on the right-hand side of the . can be a static or non-static data member, function, or member enumerator (paragraph 4 of the cited section). It cannot be a nested type. In this sense, member enumerators are syntactically similar to static const data members.
Notes:
As §13.5.6 clarifies, a->b is is subject to operator overloading. If a is not a pointer type, then -> may be overloaded, in which case the expression is interpreted as (a.operator->())->b. Eventually, the sequence of overloaded -> calls must result in a pointer type, at which point the interpretation of §5.2.5/2 is applied.
An important difference between Class::member and value.member is that in the second case, value will be evaluated even if that is unnecessary to resolve the value of member.
From C++ ISO/IEC 2011
An enumerator declared in class scope can be referred to using the
class member access operators (::, . (dot) and -> (arrow)),
The enum values are treated much as if they were static members
of the class, and can be accessed in two ways: via the class
name followed by the scope resolution operator
(MyClass::MY_VALUE0), or like any other member
(instance.MY_VALUE0 or pointer->MY_VALUE0).
Note that in the latter case, the operand on the left is still
evaluated, even though the results of the evaluation is not
used. In other words, if I write f()->MY_VALUE0 (where f()
returns a MyClass*), the function will be called, despite the
fact that its return value is not used.
Related
void foo();
class Foomatic() {
void bar();
void baz()
{
std::thread a(foo); // this compiles
std::thread b(Foomatic::bar, this); // this doesn't
std::thread c(&Foomatic::bar, this); // and this compiles
// ...
}
};
I know that the correct syntax for the pointer to member function is &Foomatic::bar.
But why exactly is Foomatic::bar incorrect? What does that one return? And why exactly is the &Foomatic::bar the correct one? It seems counter-intuitive to me.
This is not a duplicate. The question you linked to answers what the correct syntax is, not explaining the reasons why.
I'm asking why C++ is so inconsistent here, I already know what the syntax is.
C++ inherited the conversion from functions to function pointers from C: in C you could just assigne a function name to a function pointer without the need to take the address. This "decay" of function names to function pointers seems somewhat ill-advised and did cause some confusion in C.
When pointers to members where introduced there was no need to be backward compatible with C: C doesn't have pointers to members. Thus, there was the option to not have an implicit conversion from a member name to a pointer to member. Since a facility can be added later if it feels necessary but hardly removed the choice was made to not have an implicit conversion from a member name to pointer to member.
Since there is a reasonably consistent interface to get pointers to functions, pointers to members, and pointers to objects there doesn't seem to be a need to have implicit conversions from member names to pointer to member pretty much as there is no implicit conversion from an object name to a pointer to an object.
Semantically, something like T::member is a reference to a member rather than pointer to a member. However, I don't think it is possible to formulate this type with the current specification. Possibly, a future standard defines someting for this syntax.
If &Foomatic::Bar is a pointer-to-member function (because you're taking the address of the function using the address-of operator &), then Foomatic::Bar is a member function, not a pointer-to-member function.
This is exactly the same with non-member functions: if &foo is a pointer to (non-member) function, then foo is a function.
Neither C++ nor C have functions as first-class objects, e.g., you can't have a variable whose type/value is a function --- only a pointer thereto.
As a syntactic sugar special case for non-member functions, you can call said function without having to deference it first explicitly, e.g, foo(42) is a short-hand for (*foo)(42) if foo is a pointer to (non-member) function.
I am working in embedded C++ project, where I plan to make memory statically allocated as much as I can. So, I am writing a set of functions to override new/delete for all classes and for the global new/delete.
Here is a naive implementation:
class MyClass
{
int x;
float y;
double z;
static MyClass m_preAllocatedObjects[100]; //Solution 1
static char m_preAllocatedMemory[100 * sizeof(MyClass)]; //Solution 2
static char* getPreAllocatedMemory() // Solution 3
{
static char localStaticMemory[100 * sizeof(MyClass)];
return localStaticMemory;
}
static void* operator new(size_t s){
void* p; /*fill p from the pre-allocated memory or object*/;
return p;
}
};
Solution 1: It works for object with default constructor only.
Solution 2: It gives compilation error use of undefined type 'MyClass'; and this is what I am asking about.
Solution 3: This solution works fine.
The question is:
Why can I create static members of MyClass, while I can't get sizeof(MyClass)?
while I can't get sizeof(MyClass)?
The reason is that MyClass is not fully defined until the closing } of the class definition, from section 9 Classes of the c++11 standard (draft n3337):
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen.
The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
For purposes of access checking, the injected-class-name is treated as if it were a public member name. A
class-specifier is commonly referred to as a class definition. A class is considered defined after the closing
brace of its class-specifier has been seen even though its member functions are in general not yet defined.
The optional attribute-specifier-seq appertains to the class; the attributes in the attribute-specifier-seq are
thereafter considered attributes of the class whenever it is named.
and sizeof can only be applied to a complete type, from section 5.3.3 Sizeof:
The sizeof operator yields the number of bytes in the object representation of its operand. The operand is
either an expression, which is an unevaluated operand (Clause 5), or a parenthesized type-id. The sizeof
operator shall not be applied to an expression that has function or incomplete type, to an enumeration
type whose underlying type is not fixed before all its enumerators have been declared, to the parenthesized
name of such types, or to an lvalue that designates a bit-field. ...
To correct, define the size of the array outside of the class definition:
class MyClass
{
static char m_preAllocatedMemory[];
};
char MyClass::m_preAllocatedMemory[100 * sizeof(MyClass)];
To "know" the size of MyClass the compiler will need to know the whole class. When you are forward declaring a static MyClass m_preAllocatedObjects[100]; you are actually not defining the variable - to actually get the variable, you will have to do :
MyClass MyClasss::m_preAllocatedObjects[100];
somewhere in a .cpp file. This is where the memory for the objects are being "placed" as a lump in the data-segment. So the compiler doesn't have to know the actual size of MyClass at the point where you declare the variable. However, it does need to know the size to evaluate 100 * sizeof(MyClass).
You have to do that in two step:
declaring an array (without knowing its size) inside the class.
defining it, after you finish declaring the class, so that you know the size.
Here is the code:
class MyClass
{
int x;
...
static char m_preAllocatedMemory[];
};
char MyClass::m_preAllocatedMemory[100 * sizeof(MyClass)];
I was trying to implement a smart pointer class similar to the standard library auto_ptr and accordingly I had to overload the -> operator for the same. Here is my code
template <typename T>
class SmartPtr
{
T * operator -> ()
{
return _pAct;
}
private:
T * _pAct;
};
Rest of the implementation is not shown so as to avoid diversion from my query.
Now I create a SmartPtr of class A and call a method Show() present in A on it :
SmartPtr smPtr(new A);
smPtr->Show();
Here is my query(don't know if its valid also)
Since SmartPtr::operator->() return A*, the call to show should translate to (A*)Show. Why it translates to (A*)->Show() ?
or in other words how does smPtr->Show() mean call Show() on whatever smPtr->() operator returns ?
Because operator -> applies sequentially until it can't be applied any more.
13.5.6 Class member access [over.ref]
1) operator-> shall be a non-static member function taking no
parameters. It implements class member access using ->
postfix-expression -> id-expression An expression x->m is interpreted
as (x.operator->())->m for a class object x of type T if
T::operator->() exists and if the operator is selected as the best
match function by the overload resolution mechanism (13.3). (emphasis mine)
Which means, in your case, it translates to:
smPtr.operator->()->Show();
| |
returns A* call Show on the A*
This question already has answers here:
How to use a member variable as a default argument in C++?
(4 answers)
Closed 1 year ago.
struct X
{
X():mem(42){}
void f(int param = mem) //ERROR
{
//do something
}
private:
int mem;
};
Can anyone give me just one reason as to why this is illegal in C++?! That is to say, I know that it is an error, I know what the error means, I just can't understand why would this be illegal!
Your code (simplified):
struct X
{
int mem;
void f(int param = mem); //ERROR
};
You want to use a non-static member data as default value for a parameter of a member function. The first question which comes to mind is this : which specific instance of the class the default value mem belongs to?
X x1 = {100}; //mem = 100
X x2 = {200}; //mem = 200
x1.f(); //param is 100 or 200? or something else?
Your answer might be 100 as f() is invoked on the object x1 which has mem = 100. If so, then it requires the implementation to implement f() as:
void f(X* this, int param = this->mem);
which in turn requires the first argument to be initialized first before initialization of other argument. But the C++ standard doesn't specify any initialization order of the function arguments. Hence that isn't allowed. Its for the same reason that C++ Standard doesn't allow even this:
int f(int a, int b = a); //§8.3.6/9
In fact, §8.3.6/9 explicitly says,
Default arguments are evaluated each
time the function is called. The order
of evaluation of function arguments is
unspecified. Consequently, parameters
of a function shall not be used in
default argument expressions, even if
they are not evaluated.
And rest of the section is an interesting read.
An interesting topic related to "default" arguments (not related to this topic though):
Default argument in the middle of parameter list?
Default arguments have to be known at compile-time. When you talk about something like a function invocation, then the function is known at compile-time, even if the return value isn't, so the compiler can generate that code, but when you default to a member variable, the compiler doesn't know where to find that instance at compile-time, meaning that it would effectively have to pass a parameter (this) to find mem. Notice that you can't do something like void func(int i, int f = g(i)); and the two are effectively the same restriction.
I also think that this restriction is silly. But then, C++ is full of silly restrictions.
As DeadMG has mentioned above, somethig like
void func(int i, int f = g(i))
is illegal for the same reason. i suppose, however, that it is not simply a silly restriction. To allow such a construction, we need to restrict evaluation order for function parameters (as we need to calculate this before this->mem), but the c++ standard explicitly declines any assumptions on the evaluation order.
The accepted answer in the duplicate question is why, but the standard also explicitly states why this is so:
8.3.6/9:
"
Example: the declaration of X::mem1() in the following example is ill-formed because no object is supplied for the nonstatic member X::a used as an initializer.
int b;
class X
int a;
int mem1(int i = a); // error: nonstatic member a
// used as default argument
int mem2(int i = b); // OK: use X::b
static int b;
};
The declaration of X::mem2() is meaningful, however, since no object is needed to access the static member X::b. Classes, objects and members are described in clause 9.
"
... and since there exists no syntax to supply the object necessary to resolve the value of X::a at that point, it's effectively impossible to use non-static member variables as initializers for default arguments.
ISO C++ section 8.3.6/9
a nonstatic member shall not be used in a default argument expression, even if it
is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is used to form a pointer to member (5.3.1).
Also check out the example given in that section.
For one reason, because f is public, but mem is private. As such, code like this:
int main() {
X x;
x.f();
return 0;
}
...would involve outside code retrieving X's private data.
Aside from that, it would (or at least could) also make code generation a bit tricky. Normally, if the compiler is going to use a default argument, it gets the value it's going to pass as part of the function declaration. Generating code to pass that value as a parameter is trivial. When you might be passing a member of an object (possibly nested arbitrarily deeply) and then add in things like the possibility of it being a dependent name in a template, that might (for example) name another object with a conversion to the correct target type, and you have a recipe for making code generation pretty difficult. I don't know for sure, but I suspect somebody thought about things like that, and decided it was better to stay conservative, and possibly open thins up later, if a good reason was found to do so. Given the number of times I've seen problems arise from it, I'd guess it'll stay the way it is for a long time, simply because it rarely causes problems.
Compiler has to know addresses to maintain default values at compile time. Addresses of non-static member variables are unknown at compile time.
As all the other answers just discuss the problem, I thought I would post a solution.
As used in other languages without default arguments (Eg C# pre 4.0)
Simply use overloading to provide the same result:
struct X
{
X():mem(42){}
void f(int param)
{
//do something
}
void f()
{
f(mem);
}
private:
int mem;
};
Default arguments are evaluated in two distinct steps, in different contexts.
First, the name lookup for the default argument is performed in the context of the declaration.
Secondly, the evaluation of the default argument is performed in the context of the actual function call.
To keep the implementation from becoming overly complicated, some restrictions are applied to the expressions that can be used as default arguments.
Variables with non-static lifetime can't be used, because they might not exist at the time of the call.
Non-static member variables can't be used, because they need an (implicit) this-> qualification, which can typically not be evaluated at the call site.
This question already has answers here:
c++ access static members using null pointer
(5 answers)
Closed 8 years ago.
class Foo {
public:
static const int kType = 42;
};
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
Is this defined behavior? I read through the C++ standard but couldn't find anything about accessing a static const value like this... I've examined the assembly produced by GCC 4.2, Clang++, and Visual Studio 2010 and none of them perform a dereference of the NULL pointer, but I'd like to be sure.
You can use a pointer (or other expression) to access a static member; however, doing so through a NULL pointer unfortunately is officially undefined behavior. From 9.4/2 "Static members":
A static member s of class X may be
referred to using the qualified-id
expression X::s; it is not necessary
to use the class member access syntax
(5.2.5) to refer to a static member. A
static member may be referred to using
the class member access syntax, in
which case the object-expression is
evaluated.
Based on the example that follows:
class process {
public:
static void reschedule();
};
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
The intent is to allow you to ensure that functions will be called in this scenario.
I believe that the actual value of the type is not used at all when calling
bar->kType
since kType is static, and bar is of type Foo it is the same as calling
Foo::kType
which you should really be doing anyway for clarity.
Calling bar->kType gives a compiler warning on most platforms for this reason.
Apart from the issue about accessing through the NULL pointer, there is another subtle issue in the code
$9.4.2/2 - "The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition."
$9.4.2/4- "If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. 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."
class Foo {
public:
static const int kType = 42;
};
int const Foo::kType;
void Func() {
Foo *bar = NULL;
int x = bar->kType;
putc(x, stderr);
}
So, yet one more reason for UB in the OP code.
Even if it worked it is awful code.
In serious programming you code not only for yourself, but also for others who will maintain your code.
Playing tricks like this must be avoided, because you respect your colleagues.
One consequence of this code: whether the pointer is NULL or not is even not at question, but it implies that this member kType may not be a plain non-static member of the class. Sometimes classes are big (this is evil too) and one cannot always recheck the definition of each and every variable.
Be rigorous. And call all your static members only this way:
Foo::kType
Another possibility is to follow a coding convention that let know that the member is static, for example, a s_ prefix for all classes static members:
Foo::s_kType
There is a higher rule so to speak which basically says - don't even think about compiling things that are provably not used. Advanced template programming depends on this a lot, so even if it might be a bit gray-zonish when a compiler clearly sees that the result of a construct is not used it's just going to eliminate it. Especially when it's provably safe like in this case.
You may want to try a few variants if you want - like making pointer a param of a function, result of a function, leaving a pointer uninitialized (best chance for triggering compiler complaint), doing a straight cast of 0 (best chance of being conplaint-free).