0

the following code from the turorial http://www.cplusplus.com/doc/tutorial/ :

// example on this
#include <iostream>
using namespace std;

class Dummy {
public:
  bool isitme (Dummy& param);
};

bool Dummy::isitme (Dummy& param)
{
  //cout << param << endl;//this cant be printed with cout ?!
  printf("TEST3: param=%p\n",param);
  cout << "TEST4: &param=" << &param << endl;
  if (&param == this) return true;
  else return false;
}

int main () {
  Dummy a;
  Dummy* b = &a;
  cout << "TEST1: &a=" << &a << endl;
  printf("TEST2: a=%p\n",a);
  if ( b->isitme(a) )
    cout << "yes, &a is b\n";
  return 0;
}

which whith the added "TESTS" to show addresses give me the output:

TEST1: &a=0x7ffc9bdea7bf
TEST2: a=(nil)
TEST3: param=0x7ffc9bdea7bf
TEST4: &param=0x7ffc9bdea7bf
yes, &a is b

This is very confusing for me since - as far as I understand - with the pass by reference way of passing args to functions, i.e., as it is done for the "isitme" member function, when we pass an argument to it, this arg is "magically" dereferenced in the body of the function and should not contain the address of the variable (but somehow the address is "magically" i.e. automatically used to access the actual contents of course so as to modify the variable outside the function). But please clarify any inconsistencies that I might have said...

So three questions:

  1. what exactly is a? is it a pointer to the first byte of the object a in memory... it it something else... it is not clear what exactly is in a. (it does not seem to be a pointer since there is the other syntax with Dummy* a = new Dummy... but what else could it be?)

  2. why does TEST2 output (nil) (nil on my local machine after compilation, and in the online REPL it actually outputs a DIFFERENT address than all the others) ?

  3. Why does TEST3 and TEST4 give the same value for param and &param ?! (it is like if the address of "param" and the contents of "param" are the same... this is totally confusing but I suspect it has to do with the pass-by-ref "magic"?) I thought param as passed by ref would be automatically dereferenced...

P.S. Although the cpp tutorial is nice, I think they should spend a lot more time explaining this in at least a full paragraph to explain all that behavior which is not obvious at all.

http://cpp.sh/6hlpok

https://cplusplus.com/doc/tutorial/templates/

SheppLogan
  • 322
  • 3
  • 18
  • 2
    `printf("TEST2: a=%p\n",a);` This exhibits undefined behavior. `%p` specifier expects a parameter of pointer type, but `a` is not a pointer. Same with `printf("TEST3: param=%p\n",param);` – Igor Tandetnik Jan 10 '22 at 01:17
  • thanks , but in fact then WHAT is a ? XD if a is not a pointer ... I don't see what it can be – SheppLogan Jan 10 '22 at 01:18
  • 2
    An object of type `Dummy`, of course. Just like you declared it. – Igor Tandetnik Jan 10 '22 at 01:18
  • yes but object for me is == to pointer, otherwise can you explain what is contained concretely in a – SheppLogan Jan 10 '22 at 01:18
  • But to the C++ language, it is not. – Igor Tandetnik Jan 10 '22 at 01:19
  • hum maybe i m confused with Java, in Java as far as i know objects are references i.e. sort of pointers without the pointer arithmetic – SheppLogan Jan 10 '22 at 01:20
  • http://cpp.sh/6hlpok – SheppLogan Jan 10 '22 at 01:20
  • Why then does a and &a give the same value inside the isitme func ? – SheppLogan Jan 10 '22 at 01:22
  • `Dummy` has no non-static data members or base classes, so in a sense nothing is "contained concretely" in it. It has no sub-objects. If that's what you are asking. I frankly don't quite grasp the nature of your difficulty. – Igor Tandetnik Jan 10 '22 at 01:22
  • 1
    Again, `printf("TEST3: param=%p\n",param);` exhibits [undefined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior). "Seems to work as I expect" is one possible manifestation of undefined behavior. – Igor Tandetnik Jan 10 '22 at 01:23
  • ok but then maybe the most troubling thing for me is why param and &param give the same value i.e. seems to be the addresse of a in the isitme function? – SheppLogan Jan 10 '22 at 01:24
  • 1
    @SheppLogan Calling `printf` with `param` as argument is _undefined behavior_. It could produce anything. Maybe you should learn C++ [from a good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Also note that the tutorial explains variables and pointers in an earlier section. It is exactly the same for class-type variables as it is for variables of primitive type. – user17732522 Jan 10 '22 at 01:26
  • 2
    You are looking at a value printed by a function call that exhibits undefined behavior. You cannot reason or reach any conclusions about a program that exhibits undefined behavior - it can do [absolutely anything](http://catb.org/jargon/html/N/nasal-demons.html). Including conforming to your preconceived notions, purely by accident. Undefined behavior is undefined. – Igor Tandetnik Jan 10 '22 at 01:26
  • ok I get the undefined thing yes. But, what seems confusing is that in an ordinary function with pass by ref e.g., int myfunc(int& a){...} then you can use a directly (withtout the &) as if it was "automatically" dereferenced i.e. as if you used *a, then why can't you use "param" withtout the &? – SheppLogan Jan 10 '22 at 01:29
  • and yes i ve read the tutorial and i do have some experience about pointers, but I noticed they did not explain adequately in my opinion the pass by ref with respect to pointers, since pass by ref was explained before pointers, ( which does not make much sense in my opinion) – SheppLogan Jan 10 '22 at 01:31
  • @SheppLogan A reference refers directly to the object it is bound to as if you named that object itself. But to get a pointer to an object you need to use `&` on the name of the object. So you also need that if you want to have a pointer to the object that the reference references. – user17732522 Jan 10 '22 at 01:31
  • "_ok I get the undefined thing yes. But..._" - Nightmares starts at that "but". With _undefined behavior_ your compiler may have come up with assembly code you couldn't even imagine. – Ted Lyngmo Jan 10 '22 at 01:33
  • Ok, but do you agree to say that a reference is in fact a pointer but without the pointer arithmetic possibilities and with the dereferencing mechanism hidden to the programmer= – SheppLogan Jan 10 '22 at 01:34
  • @SheppLogan No, references are fundamentally not pointers. They are implemented by the compiler as pointers, but on a language level they are completely different. https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in – user17732522 Jan 10 '22 at 01:35
  • haha ok Ted, but you do agree that in e.g., int myfunc(int& a){...} then you can use "a" directly (withtout the &) as if it was "automatically" dereferenced i.e. as if you used *a ... ? – SheppLogan Jan 10 '22 at 01:35
  • @SheppLogan Sure, if `myfunc` is passed a proper reference to `a`, no problem. It'd just be a non-owning "shell" for the real thing but using it would be just like using an automatic (in most cases). – Ted Lyngmo Jan 10 '22 at 01:37
  • @SheppLogan If `a` is a reference `*a` would _not_ give you the object that the reference is bound to. It would apply the `*` operator to the object that the reference is bound to instead. `a` will instead _directly_ refer to the object it is bound to. – user17732522 Jan 10 '22 at 01:38
  • Ok, maybe I understand now, see my "own answer" below, so "param" or "a" in this situation is actually the raw memory values constituting the object – SheppLogan Jan 10 '22 at 01:45

2 Answers2

0

It works as expected if you pass the addresses to the printfs:

#include <iostream>
using namespace std;

class Dummy {
public:
  bool isitme (Dummy& param);
};

bool Dummy::isitme (Dummy& param)
{
  //cout << param << endl;//this cant be printed with cout ?!
  printf("TEST3: &param=%p\n", &param);
  cout << "TEST4: &param=" << &param << endl;
  if (&param == this) return true;
  else return false;
}

int main () {
  Dummy a;
  Dummy* b = &a;
  cout << "TEST1: &a=" << &a << endl;
  printf("TEST2: &a=%p\n", &a);
  if ( b->isitme(a) )
    cout << "yes, &a is b\n";
  return 0;
}
TEST1: &a=0x7ffc9dd881df
TEST2: &a=0x7ffc9dd881df
TEST3: &param=0x7ffc9dd881df
TEST4: &param=0x7ffc9dd881df
yes, &a is b

What you did originally was undefined behaviour and the result can change between compilers.

C is weakly typed and printf can accept things that do not make sense.

Adriel Jr
  • 2,451
  • 19
  • 25
  • my question really is why do printf("TEST3: param=%p\n",param); cout << "TEST4: &param=" << &param << endl; output the same value ? – SheppLogan Jan 10 '22 at 01:26
  • 1
    @SheppLogan `printf("TEST3: param=%p\n",param)` is **undefined behavior**, plain and simple. `%p` requires a pointer, but `param` is NOT a pointer, so that code can print literally *ANYTHING*. You can't expect anything reasonable from it. You don't seem to be grasping this concept very well. Any chance of it printing what you are expecting is **purely coincidence** – Remy Lebeau Jan 10 '22 at 01:43
  • yes sorry I think I get it now, it does not make sense to print it this way. – SheppLogan Jan 10 '22 at 01:45
  • In the "answer" i wrote to my own question, i actually put values in this object and I see that printing "param" now prints the actual raw memory data – SheppLogan Jan 10 '22 at 01:46
  • See: [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/q/2397984/3422102) and [What is indeterminate behavior in C++ ? How is it different from undefined behavior?](https://stackoverflow.com/q/11240484/3422102) and [Undefined behavior](https://en.cppreference.com/w/c/language/behavior) – David C. Rankin Jan 10 '22 at 03:22
0

Ok, I think doing this clarifies things for me:

// example on this
#include <iostream>
using namespace std;

class Dummy {

public:
  int x;
  int y;
  Dummy(int a,int b){x=a;y=b;};
  bool isitme (Dummy& param);
};

bool Dummy::isitme (Dummy& param)
{
  printf("x=%d\n", param.x);
  //cout << param << endl;//this cant be printed with cout ?!
  printf("TEST4: param=%p\n",param);
  cout << "TEST5: &param=" << &param << endl;
  if (&param == this) return true;
  else return false;
}

int main () {
  Dummy a(5,6);
  Dummy* b = &a;
  cout << "TEST1: &a=" << &a << endl;
  printf("TEST2: a=%p\n",a);
  printf("TEST3: &a = %p \n",&a);
  if ( b->isitme(a) )
    cout << "yes, &a is b\n";
  return 0;
}

the output is then:

TEST1: &a=0x7ffca1f51280
TEST2: a=0x600000005
TEST3: &a = 0x7ffca1f51280
x=5
TEST4: param=0x600000005
TEST5: &param=0x7ffca1f51280
yes, &a is b

and now in fact I see that "param" is the raw memory occupied by the data i.e., TEST4: a=0x600000005 , i.e. values 5 and 6 , in the object it seems!

SheppLogan
  • 322
  • 3
  • 18
  • 1
    "*I see that "param" is the raw memory occupied by the data in the object*" - correct. In `printf("TEST4: param=%p\n",param);`, you are putting the object on the function's call stack, and then telling `printf()` to interpret the first 8 bytes of that object as if they were a memory address, which they are not. As for why `cout << param` doesn't work, it is simply because you didn't define an `operator<<` for outputting `Dummy` to an `std::ostream` yet. – Remy Lebeau Jan 10 '22 at 01:48
  • ok nice, and you mention the call stack because I did not use the "new" keyword otherwise it would have been allocated in the heap – SheppLogan Jan 10 '22 at 01:49
  • and more precisely, correct to say that Dummy a(5,6) is in the main's call stack (because of no use of the new keyword) and then is copied into the isitme call stack, like a pass by value in fact? – SheppLogan Jan 10 '22 at 01:53
  • 1
    "*... and then is copied into the isitme call stack, like a pass by value in fact?*" - no, because `isitme()` takes its parameter by reference, so there is no copy made. But there is a copy made when that parameter is passed to `printf()` by value. – Remy Lebeau Jan 10 '22 at 01:55
  • oh yes sorry isitme ... pass by ref indeed... but do you mean that the whole object data was then copied into the args of the printf function ? which makes sense since printf is not supposed to modify anything, just to print – SheppLogan Jan 10 '22 at 02:34
  • "*the whole object data was then copied into the args of the printf function?*" - yes. That is what pass-by-value does. "*printf is not supposed to modify anything, just to print*" - `printf()` is a C function, it has no concept of objects, and no print specifiers are appropriate for objects, except maybe for `%p` to print the memory address of an object. Which it can't get from a parameter that is passed in by value. – Remy Lebeau Jan 10 '22 at 02:36