This question already has answers here:
Type qualifier appear in multiple item declaration (exhibiting strange behavior with pointer)
(2 answers)
Closed last month.
I know
int* p, k;
declares k to be int and p to be int*, but how about:
static int a, b;
const int c, d;
and other declarators. Is it the same for all of them? Obviously for pointers, arrays, and indirection it would be.
I'm not asking if it compiles; I'm asking for rules regarding these declarations, preferably quoted from the standard.
It doesn't take much to test this. The following does not compile because p has been declared const. https://godbolt.org/z/P7bj85aWx
int main() {
const int k = 1, p = 5;
p++;
return 0;
}
For static, consider the following which outputs 67 rather than 66. The latter would be expected if b were not static.
https://godbolt.org/z/E58azYdfe.
#include <iostream>
int foo() {
static int a, b = 5;
b++;
return b;
}
int main() {
std::cout << foo() << foo() << std::endl;
return 0;
}
Related
[edit: Here is the motivation: passing a pointer of a variable to an external function may accidentally break some optimization for "adjacent" variables, because of the possibility to get pointers to the adjacent variables calculated from the original pointer by the external function. The following is the original post, in which the volatile is to simulate an external function inaccessible to the current compiler unit, e.g. virtual function call, closed source library function, etc.]
I wondered if the return t.a; in the following code would be optimized to return 0;.
//revision 1
struct T
{
int a;
int b;
};
void f_(int * p)
{
*p = 1;
}
auto volatile f = f_;
int main()
{
T t;
t.a = 0;
t.b = 0;
for (int i = 0; i < 20; ++i)
{
f(&t.b);
}
return t.a;
}
Well it's not.
Fair enough because the code in function f may use offsetof to acquire a pointer to t then change t.a.
So it's not safe to optimize the load of t.a away.
[edit: At a second thought, offsetof is not enough here. We need container_of, which there seems no way to implement in standard C++.]
But offsetof cannot be used on non-standard-layout types. So I tried the following code:
//revision 2
#include <type_traits>
struct T
{
private:
char dummy = 0;
public:
int a;
int b;
};
static_assert(!std::is_standard_layout_v<T>);
void f_(int * p)
{
*p = 1;
}
auto volatile f = f_;
int main()
{
T t;
t.a = 0;
t.b = 0;
for (int i = 0; i < 20; ++i)
{
f(&t.b);
}
return t.a;
}
Unfortunately it's still not working.
My questions are:
whether it's safe to optimize the load of t.a away in the above case (revision 2)
if it's not, is there some arrangement in existence/proposal to make it possible? (e.g. making T a more special type, or some attribute specifier for member b in T)
P.S. The following code is optimized for return t.a;, but the yielded code for the loop is a bit inefficient.
And still, the temporary variable juggling is cumbersome.
//revision 3
struct T
{
int a;
int b;
};
void f_(int * p)
{
*p = 1;
}
auto volatile f = f_;
int main()
{
T t;
t.a = 0;
t.b = 0;
for (int i = 0; i < 20; ++i)
{
int b = t.b;
f(&b);
t.b = b;
}
return t.a;
}
The use of offsetof to reach T::a from T::b is illegitimate, since there is no object pointer-interconvertible with T::b from which T::a can be reached. In the other direction it is possible to reach T::b from T::a, since the latter is pointer-interconvertible with T. Contra Peter in comments (and despite the existence of container_of macro in e.g. Linux kernel), &t.b - 1 does not yield a pointer to t.a, since T::b and T::a are not pointer-interconvertible.
Note that given a pointer to T::a you would still need to use std::launder to access T::b:
auto p = &t.a;
std::launder(reinterpret_cast<T*>(p))->b = 1;
So a sufficiently aggressive compiler would indeed be able to conclude that no replacement f could access t.a given a pointer to t.b. However, it appears that no mainstream compiler performs this optimization at this time.
I am working on const-correctness of my code and just wondered why this code compiles:
class X
{
int x;
int& y;
public:
X(int& _y):y(_y)
{
}
void f(int& newY) const
{
//x = 3; would not work, that's fine
y = newY; //does compile. Why?
}
};
int main(int argc, char **argv)
{
int i1=0, i2=0;
X myX(i1);
myX.f(i2);
...
}
As far as I understand, f() is changing the object myX, although it says to be const. How can I ensure my compiler complains when I do assign to y? (Visual C++ 2008)
Thank a lot!
Because you are not changing any variable in X. Actually, you are changing _y which is an outsider with respect to your class. Don't forget that:
y = newY;
Is assigning the value of newY to the variable pointed by y, but not the references them selves. Only on initialization the references are considered.
The situation is similar to pointer members. In a const member function, the const applies to the pointer itself, not the pointee.
It's the difference between:
X* const //this is how the const applies: you can modify the pointee
const X*
Except X& const isn't valid syntax, since the reference can't be made to refer to another object in the first place (they are implicitly always const). In conclusion: const on methods has no effect on member references.
As additional information for the accepted answer, I want to say, in fact one can
change variables in X.
Because you are not changing any variable in X.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Bar {
public:
void funcA() const {
c++;
}
int b = 3;
int &c = b;
};
int main()
{
Bar b;
b.funcA();
cout << b.b << endl; //4
}
So the main idea for this problem is:
It modifies what the member refers to, it does not modify the member.
This also applies for pointer members.
See here Why can reference members be modified by const member functions?
This question already has answers here:
What are the pointer-to-member operators ->* and .* in C++?
(7 answers)
Closed 7 years ago.
Good day,
I've come across this question, but I'm specifically interested in the "object pointed to by member ..." type operators as listed here on Wikipedia.
I have never seen this in the context of actual code, so the concept appears somewhat esoteric to me.
My intuition says they should be used as follows:
struct A
{
int *p;
};
int main()
{
{
A *a = new A();
a->p = new int(0);
// if this did compile, how would it be different from *a->p=5; ??
a->*p = 5;
}
{
A a;
a.p = new int(0);
// if this did compile, how would it be different from *a.p=5; ??
a.*p = 5;
}
return 0;
}
But this doesn't compile because p is undeclared. (See example)
Could anyone please provide a real-world example of the use of operator->* and/or .* in C++?
Those operators are used for pointer-to-member objects. You won't come across them very often. They can be used to specify what function or member data to use for a given algorithm operating on A objects, for instance.
Basic syntax:
#include <iostream>
struct A
{
int i;
int geti() {return i;}
A():i{3}{}
};
int main()
{
{
A a;
int A::*ai_ptr = &A::i; //pointer to member data
std::cout << a.*ai_ptr; //access through p-t-m
}
{
A* a = new A{};
int (A::*ai_func)() = &A::geti; //pointer to member function
std::cout << (a->*ai_func)(); //access through p-t-m-f
}
return 0;
}
The ->* and .* syntax is the "pointer-to-member" operator that can be used to store pointers to members of a very specific object.
Usage example:
class A {
public: int x;
};
int main() {
A obj;
int A::* memberPointer = &A::b; //Pointer to b, which is int, which is member of A
obj.*memberPointer = 42; //Set the value via an object
A *objPtr = &obj;
objPtr->*memberPointer = 21; //Set the value via an object pointer
}
I am using function overload to have a general version of a behaviour and a more usual one. The usual function just picks a default value for the second argument that actually depends on the first, and the compiler is giving me an error because it does not even recognize the existence of the second function. I also tried to do it with default values, but because the default depends on the first argument, the compiler does not seem to accept it.
So, here are simplified examples just for illustration.
Function overloading case:
#include <stdio.h>
struct pair {
int x;
int y;
};
int func(pair a){
return func(a, a.y);
}
int func(pair a, int b) {
return a.x*b;
}
int main() {
pair z;
z.x = 2;
z.y = 4;
printf("%d\n", func(z));
printf("%d\n", func(z,12));
}
This gives me the error:
a.c: In function ‘int func(pair)’:
a.c:9:21: error: too many arguments to function ‘int func(pair)’
a.c:8:5: note: declared here"
Example with default values:
#include <stdio.h>
struct pair {
int x;
int y;
};
int func(pair a, int b = a.y) {
return a.x*b;
}
int main() {
pair z;
z.x = 2;
z.y = 4;
printf("%d\n", func(z));
printf("%d\n", func(z,12));
}
Gives me the following error: "local variable a may not appear in this context"
So, is there any way in C++ to emulate this behaviour? I never had this problem in other languages, like Java or even in ASP.
Thank you all.
In C and C++, before the function call, that function should be declared or defined. Here you are making a call to return func(a, a.y); but the function func(pair, int) has not yet been declared or defined.
You need to change the definitions of the two functions, or just declare the functions in the beginning of your code. As other answers have explained the first approach, here is the snippet with second approach.
#include <stdio.h>
//Function Declaration
int func(pair);
int func(pair, int);
struct pair {
int x;
int y;
};
int func(pair a){
return func(a, a.y);
}
int func(pair a, int b) {
return a.x*b;
}
int main() {
pair z;
z.x = 2;
z.y = 4;
printf("%d\n", func(z));
printf("%d\n", func(z,12));
}
Switch the order of the definitions of func(), such that the 2 argument version is defined before the one argument version. The compiler doesn't know the 2 argument version exists until it encounters the definition, so you can't call it until you've told the compiler it exists.
You have to change the order of the definitions:
int func(pair a, int b) {
return a.x*b;
}
int func(pair a){
return func(a, a.y);
}
LIVE DEMO
This is happening because in int func(pair a) you are calling int func(pair a, int b) which is not visible. Changing the order of definitions like above solves this problem.
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 9 years ago.
Is my function has undefined behavior? Becouse there is local variable c, so its in automatic location so it will be destruct after execution of function? (end of scope)
int* calculate(int* a,int* b)
{
int c=(*a)+(*b); //local variable c
return &c;
}
int main()
{
int a=12;
int b=23;
int* ptr=calculate(&a,&b);
std::cout<<*ptr<<endl;
}
Yes, returning a pointer to a temporary local object and dereferencing that is undefined behavior.
Because after exiting the function calculate, that object goes out of scope and automatically will be destroyed, then the provided pointer, points to an invalid address and it's a dangling pointer. After that, you can use dereference and use it (for example: *ptr).
In your case, you can use a normal variable, remove those *:
int calculate(int *a, int *b)
{
int c = (*a)+(*b);
return c;
}
since you have nothing reasonable to pass them by pointer, it's better to remove more *:
int calculate(int a, int b)
{
int c = a + b;
return c;
}
You can pass an int declared in the main, to calculate, like this::
void calculate(int* a,int* b, int* c)
{
*c=(*a)+(*b);
return ;
}
int main()
{
int a=12;
int b=23;
int c=0;
calculate(&a,&b,&c);
std::cout<<c<<endl;
return 0;
}
The much more simpler way is::
int Calculate( int a, int b )
{
return a+b ;
}
int main( void )
{
int a=12, b=23;
std::cout<<Calculate(a,b)<<endl;
return 0;
}