6

As far as I know each created object has its own address, and each object's method also has its own address. I want to verify that with the following idea:

Step 1: Build class A with public method, its name is "method".

Step 2: Create two objects in class A, they are object "b" and object "c".

Step 3: Access the addresses of "b.method" and "c.method" to check that they are equal by using a function pointer.

But I met the problem in step 3 and have found every way to solve but failed. So I posted up here to ask people to help me how to verify what I said above. Thanks everyone! And here is my C++ code:

#include<iostream>
using namespace std;
class A
{
  public:
     int a;
     void method()
     {
       //do something
     }
     static void (*fptr)();
};
int main()
{
    A b, c;

    A::fptr= &(b.method);  //error: cannot convert 'A::method' from type 
                           // 'void(A::)()' to type 'void (*)()'
    cout << A::fptr << endl;
    A::fptr= &(c.method);  //error: cannot convert 'A::method' from type  
                           //'void(A::)()' to type 'void (*)()'
    cout << A::fptr << endl;
    return 0;
}
TaQuangTu
  • 1,734
  • 2
  • 12
  • 26

4 Answers4

4

Member functions are not like typical functions. The main difference is the way they are called (they have an implicit this argument), but that difference is enough for the language to demand a new way of defining pointers to them. See here for more details.

The following code prints the address in memory of a method:

#include <iostream>

class A {
public:
    void method() {
    }
};

int main() {
    auto ptr = &A::method;
    std::cout << reinterpret_cast<void*>(ptr) << "\n";

    return 0;
}

As you can see, I had to cast the pointer to a void* to fool the compiler. G++ prints out a warning on that line, but otherwise does what you want with it.

Notice that the type of ptr is void (A::*)(), i.e. "a pointer to a method in A that receives no arguments and returns void". A pointer to methods in your B and C may be slightly different. They should convert to pointers to A, so you might want to go through that when comparing (or just cast to void* and ignore the warning).

Edited to add: It seems no cast is needed for comparison. You can just directly compare the two pointers to methods, and they will return true or false correctly.

Shachar Shemesh
  • 7,753
  • 4
  • 23
  • 54
1

The compiler and linker does not have to give distinct functions, distinct implementations.

On at least some platforms, the compiler will spot that 2 functions have the same implementation, and merge the 2 functions into a single piece of code. That limits the amount of bloat added by the template system, but stops it being a guaranteed behavior to identify different member functions.

The compiler can

  • inline all the examples of a single piece of code, and the result is it doesn't have an address.
  • share implementations where the code is the same.
  • create multiple implementations of the same function if it thinks it can be done faster.

When C++ was invented, there was a lot of effort to ensure that a C++ compilation unit was able to call a C compilation unit, and the result of this effort, was that many items of the C++ implementation became visible using compatibility tricks.

The C++ pointer to member function had no backwards-compatibility baggage, and thus no reason to allow it to be inspected. As such it is an opaque item, which can be implemented in multiple ways.

mksteve
  • 12,218
  • 3
  • 25
  • 48
  • Sharing implementation and having the same pointer are not the same. The specification specifies that pointer to non-virtual member functions compare equal if and only if they refer to the same member (Equality operators in C++11), and function only if they point to the same function. Not "same function or a function that behaves the same". – Hans Olsson Sep 13 '17 at 08:11
  • @HansOlsson From this answer https://stackoverflow.com/questions/26533740/do-distinct-functions-have-distinct-addresses there seems to be evidence that compilers do fold implementation. It is unclear as to whether taking the address of a function, or adding a comparison creates a broken implementation or forces the compiler to not make such an optimization. – mksteve Sep 13 '17 at 08:47
  • Folding implementations is ok in itself. And the conclusion at the end of the first answer is that it is incorrect if that influences pointer comparison: "It is not conforming to turn two functions to have same address ... Taking the address of a function is observable behavior and therefore folding identical functions would violate the as-if rule. " – Hans Olsson Sep 13 '17 at 09:11
1

Thank you everyone! I've been wondering about this for a long time, and now I've figured out the answer myself, there's only one "method()" that's created on memory, even if there are hundreds of objects created. All objects created that want to use this method will have to find the address of this method. Here is the code to prove what I said:

#include<iostream>
using namespace std;
class A
{
 public:
    int a;
    void method()
    {
       //do something
    }
    static void (*fptr)();
};
int main()
{
    A b,c;
    if(&(b.method)==&(c.method))
    {
        cout<<"they are same\n";
    }
    else
    {
        cout<<"they are not same\n";
    }
    return 0;
}
TaQuangTu
  • 1,734
  • 2
  • 12
  • 26
0

In your example there is only one copy of the method in memory. But i cannot think of any easy way to verify that. You can make thousands of objects and see the memory consumption. You can explore the memory occupied by your object in debugger. The memory consumption may be affected by operating system strategy for assigning memory to process. You can also explore disassembly at https://gcc.godbolt.org/ Relevant start for you would be https://godbolt.org/g/emRYQy

raven
  • 11
  • 3