Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #83984 > unrolled thread

nullptr is not 0

Started bySam <sam@email-scan.com>
First post2022-05-08 09:45 -0400
Last post2022-05-19 20:52 -0700
Articles 20 on this page of 37 — 9 participants

Back to article view | Back to comp.lang.c++


Contents

  nullptr is not 0 Sam <sam@email-scan.com> - 2022-05-08 09:45 -0400
    Re: nullptr is not 0 "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-05-08 16:21 +0200
    Re: nullptr is not 0 Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-08 10:00 -0700
    Re: nullptr is not 0 Bonita Montero <Bonita.Montero@gmail.com> - 2022-05-09 06:38 +0200
    Re: nullptr is not 0 Juha Nieminen <nospam@thanks.invalid> - 2022-05-09 05:06 +0000
      Re: nullptr is not 0 Vir Campestris <vir.campestris@invalid.invalid> - 2022-05-09 21:46 +0100
        Re: nullptr is not 0 Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-09 13:57 -0700
          Re: nullptr is not 0 Juha Nieminen <nospam@thanks.invalid> - 2022-05-10 05:04 +0000
            Re: nullptr is not 0 Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-09 22:33 -0700
        Re: nullptr is not 0 scott@slp53.sl.home (Scott Lurndal) - 2022-05-09 21:56 +0000
          Function pointer size (was Re: nullptr is not 0) Vir Campestris <vir.campestris@invalid.invalid> - 2022-05-17 21:30 +0100
            Re: Function pointer size (was Re: nullptr is not 0) scott@slp53.sl.home (Scott Lurndal) - 2022-05-17 21:00 +0000
              Re: Function pointer size (was Re: nullptr is not 0) Vir Campestris <vir.campestris@invalid.invalid> - 2022-05-19 21:52 +0100
              Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 14:08 -0700
            Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-17 17:05 -0700
            Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-18 04:46 +0000
              Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-18 02:14 -0700
                Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-19 14:53 +0000
                  Re: Function pointer size (was Re: nullptr is not 0) "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2022-05-19 17:19 +0200
                    Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 10:14 -0700
                      Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 13:45 -0400
                        Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 11:31 -0700
                      Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-20 06:58 +0000
                        Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-20 00:11 -0700
                  Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 12:27 -0400
                    Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 09:47 -0700
                      Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 13:36 -0400
                        Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 11:24 -0700
                          Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-19 21:32 -0400
                            Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 20:28 -0700
                              Re: Function pointer size (was Re: nullptr is not 0) Richard Damon <Richard@Damon-Family.org> - 2022-05-20 10:57 -0400
                  Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 09:35 -0700
                    Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-19 10:10 -0700
                    Re: Function pointer size (was Re: nullptr is not 0) Juha Nieminen <nospam@thanks.invalid> - 2022-05-20 07:15 +0000
            Re: Function pointer size (was Re: nullptr is not 0) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2022-05-18 11:50 -0700
              Re: Function pointer size (was Re: nullptr is not 0) Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-05-18 15:46 -0700
                Re: Function pointer size (was Re: nullptr is not 0) "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2022-05-19 20:52 -0700

Page 1 of 2  [1] 2  Next page →


#83984 — nullptr is not 0

FromSam <sam@email-scan.com>
Date2022-05-08 09:45 -0400
Subjectnullptr is not 0
Message-ID<cone.1652017546.512687.21572.1004@monster.email-scan.com>

[Multipart message — attachments visible in raw view] — view raw

C++ still surprises me, after so many years. After executing the following:

ptr=nullptr;

an inspection of ptr in gdb shows that it's not 0. Even after

ptr=0;

this crazy pointer object is still not 0.

That's because ptr is a pointer to a class member:

struct x {
   int y;
};

int x::*ptr;

and assigning &x::y to it results in a 0 value. Which is a valid member  
pointer. And assigning nullptr or constant 0 to ptr produces an actual value  
of -1.

I suppose that a compiler could choose to simply add 1 to the actual offset  
of a class member and use that for class member pointers, with nullptr or 0  
being an actual 0. But that's what gcc does: nullptr is not 0.

[toc] | [next] | [standalone]


#83985

From"Alf P. Steinbach" <alf.p.steinbach@gmail.com>
Date2022-05-08 16:21 +0200
Message-ID<t58jkg$qvr$1@dont-email.me>
In reply to#83984
On 8 May 2022 15:45, Sam wrote:
> C++ still surprises me, after so many years. After executing the following:
> 
> ptr=nullptr;
> 
> an inspection of ptr in gdb shows that it's not 0. Even after
> 
> ptr=0;
> 
> this crazy pointer object is still not 0.
> 
> That's because ptr is a pointer to a class member:
> 
> struct x {
>    int y;
> };
> 
> int x::*ptr;
> 
> and assigning &x::y to it results in a 0 value. Which is a valid member 
> pointer. And assigning nullptr or constant 0 to ptr produces an actual 
> value of -1.
> 
> I suppose that a compiler could choose to simply add 1 to the actual 
> offset of a class member and use that for class member pointers, with 
> nullptr or 0 being an actual 0. But that's what gcc does: nullptr is not 0.
> 

Best think of a data member pointer as an offset in the object that 
contains the member.


Cheers,

- Alf

[toc] | [prev] | [next] | [standalone]


#83988

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-05-08 10:00 -0700
Message-ID<t58t02$5m2$1@dont-email.me>
In reply to#83984
On 5/8/2022 6:45 AM, Sam wrote:
> C++ still surprises me, after so many years. After executing the following:
> 
> ptr=nullptr;
> 
> an inspection of ptr in gdb shows that it's not 0. Even after
> 
> ptr=0;
> 
> this crazy pointer object is still not 0.
> 
> That's because ptr is a pointer to a class member:
> 
> struct x {
>    int y;
> };
> 
> int x::*ptr;
> 
> and assigning &x::y to it results in a 0 value. Which is a valid member 
> pointer. And assigning nullptr or constant 0 to ptr produces an actual 
> value of -1.
> 

Yes, that's a rather well-known example. Yes, null pointer value for 
such pointers is not zero. You can also declare such variables with 
static storage duration and the compiler will have to ensure it is not 
zero at startup. And so on...

P.S. One detail that might be worth noting is that C++ type 
classification separates "pointers" and "pointers to non-static class 
members" into two different categories of types. Your example belongs to 
the second category, which kinda reduces its impressive impact )))

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#83992

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-05-09 06:38 +0200
Message-ID<t5a5qr$bl$1@dont-email.me>
In reply to#83984
Am 08.05.2022 um 15:45 schrieb Sam:
> C++ still surprises me, after so many years. After executing the following:
> 
> ptr=nullptr;
> 
> an inspection of ptr in gdb shows that it's not 0. Even after
> 
> ptr=0;
> 
> this crazy pointer object is still not 0.
> 
> That's because ptr is a pointer to a class member:
> 
> struct x {
>    int y;
> };
> 
> int x::*ptr;
> 
> and assigning &x::y to it results in a 0 value. Which is a valid member 
> pointer. And assigning nullptr or constant 0 to ptr produces an actual 
> value of -1.
> 
> I suppose that a compiler could choose to simply add 1 to the actual 
> offset of a class member and use that for class member pointers, with 
> nullptr or 0 being an actual 0. But that's what gcc does: nullptr is not 0.

I think that it would be the best that this offset-pointer
is would be (size_t)1 << sizeof(size_t) * CHAR_BIT - 1.
So it's likely that when you try to access an undefined member
with a nullptr-"offset" you will land in kernel-space and you
have a crash;

[toc] | [prev] | [next] | [standalone]


#83994

FromJuha Nieminen <nospam@thanks.invalid>
Date2022-05-09 05:06 +0000
Message-ID<t5a7h3$od0$1@gioia.aioe.org>
In reply to#83984
Sam <sam@email-scan.com> wrote:
> int x::*ptr;

Member function pointers shouldn't really be thought of as normal pointers.
They are rather different beasts, behave differently in many respects, and
you can't even convert from member-function-pointer to regular-pointer and
back safely because they are completely incompatible with each other.
They are likely not even the same size.

[toc] | [prev] | [next] | [standalone]


#84010

FromVir Campestris <vir.campestris@invalid.invalid>
Date2022-05-09 21:46 +0100
Message-ID<t5buj0$od3$1@dont-email.me>
In reply to#83994
On 09/05/2022 06:06, Juha Nieminen wrote:
> Member function pointers shouldn't really be thought of as normal pointers.
> They are rather different beasts, behave differently in many respects, and
> you can't even convert from member-function-pointer to regular-pointer and
> back safely because they are completely incompatible with each other.
> They are likely not even the same size.

_Likely_ not even the same size?

I've worked on architectures where they aren't - some of the '286 
models, for example - but it's not common, and I certainly wouldn't call 
it likely.

Andy

[toc] | [prev] | [next] | [standalone]


#84012

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-05-09 13:57 -0700
Message-ID<t5bv6v$ht7$1@dont-email.me>
In reply to#84010
On 5/9/2022 1:46 PM, Vir Campestris wrote:
> On 09/05/2022 06:06, Juha Nieminen wrote:
>> Member function pointers shouldn't really be thought of as normal 
>> pointers.
>> They are rather different beasts, behave differently in many respects, 
>> and
>> you can't even convert from member-function-pointer to regular-pointer 
>> and
>> back safely because they are completely incompatible with each other.
>> They are likely not even the same size.
> 
> _Likely_ not even the same size?
> 
> I've worked on architectures where they aren't - some of the '286 
> models, for example - but it's not common, and I certainly wouldn't call 
> it likely.

Er... what?

Virtually every single implementation out there has member function 
pointers of size different from regular pointers. This is more than 
"likely", this is basically _guaranteed_.

It is very difficult (if at all possible) to implement proper member 
function pointers without having to embed some extra information into 
them, thus bloating their size. I've heard somewhere about such 
implementations but I'm not sure they were conformant.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#84015

FromJuha Nieminen <nospam@thanks.invalid>
Date2022-05-10 05:04 +0000
Message-ID<t5crob$bf4$1@gioia.aioe.org>
In reply to#84012
Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
> It is very difficult (if at all possible) to implement proper member 
> function pointers without having to embed some extra information into 
> them, thus bloating their size.

Isn't that true only for pointers to virtual functions (due to how they
have to work)? Pointers to regular member functions wouldn't need any
extra info.

I don't know if there's anything in the semantics of the language, or
some standard requirement, that requires that all member function
pointers be the same size (regardless of whether it's a virtual
function or not).

[toc] | [prev] | [next] | [standalone]


#84018

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-05-09 22:33 -0700
Message-ID<t5ctfr$e3k$1@dont-email.me>
In reply to#84015
On 5/9/2022 10:04 PM, Juha Nieminen wrote:
> Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
>> It is very difficult (if at all possible) to implement proper member
>> function pointers without having to embed some extra information into
>> them, thus bloating their size.
> 
> Isn't that true only for pointers to virtual functions (due to how they
> have to work)? Pointers to regular member functions wouldn't need any
> extra info.
> 

Pointers to member functions do need to store extra information to 
properly handle contra-variant conversions and calls in 
multiple-inheritance contexts. The language specification permits you to 
forcefully `static_cast` pointers to members of `Derived` to pointers to 
members of `Base` even if said member does not exist in the base.

Furthermore, you are allowed to dereference such pointers using a 
reference/pointer to `Base` as long as the dynamic-type of the 
referenced object is `Derived`. Otherwise, the behavior is undefined. 
I.e. the validity of the call is determined at run time.

Here's an example

   #include <iostream>

   struct Base1 { int b = 1; };
   struct Base2
   {
     int b = 2;
     void foo() { std::cout << b << std::endl; }
   };

   struct Derived : Base1, Base2
   {
     int d = 42;
     void bar() { std::cout << d << std::endl; }
   };

   void invoke(Base2 *b, void (Base2::*pfb)())
   {
     (b->*pfb)();
   }

   int main()
   {
     void (Base2::*pfb1)() = &Base2::foo;
     void (Derived::*pfd)() = &Derived::bar;

     void (Base2::*pfb2)() = static_cast<void (Base2::*)()>(pfd); // 1

     Derived d;
     Base2 *pb = &d;
     assert((void *) pb != (void *) &d);

     invoke(pb, pfb1); // 2 OK, calls `d.foo()`
     invoke(pb, pfb2); // 3 OK, calls `d.bar()`

     Base2 b2;
     invoke(&b2, pfb1); // 4 OK, calls `b2.foo()`
     invoke(&b2, pfb2); // 5 UB
   }

The `static_cast` at point 1 is allowed by contra-variant 
pointer-to-member conversion rules.

Now, invocations of member functions through pointers at points 2 and 3 
are perfectly legal.

The most interesting invocation is the one at 3: it is legal 
specifically because `pb` actually points to a `Derived` object. 
However, in order to properly invoke `Derived::bar` the compiler will 
have to supply proper `this` pointer value to `Derived::bar`. And this 
is non-trivial, since that value is numerically different from `pb` 
(because of multiple inheritance). The adjustment of `this` pointer 
value has to occur at run time. And that is where the extra information 
stored in the pointer (base-to-derived offset) comes into the picture.

Invocation at 4 is also legal, while invocation at 5 leads to UB since 
`&b2` does not point to a `Derived` object.

The necessity to support run-time adjustment of `this` pointer when 
calling member functions from other levels of hierarchy is the reason 
member function pointers are forced to store the "offset" value in 
addition to the function entry address.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#84014

Fromscott@slp53.sl.home (Scott Lurndal)
Date2022-05-09 21:56 +0000
Message-ID<66geK.6522$lQq1.6208@fx43.iad>
In reply to#84010
Vir Campestris <vir.campestris@invalid.invalid> writes:
>On 09/05/2022 06:06, Juha Nieminen wrote:
>> Member function pointers shouldn't really be thought of as normal pointers.
>> They are rather different beasts, behave differently in many respects, and
>> you can't even convert from member-function-pointer to regular-pointer and
>> back safely because they are completely incompatible with each other.
>> They are likely not even the same size.
>
>_Likely_ not even the same size?

With g++ on linux, sizeof(member function pointer) returns
16 bytes.

[toc] | [prev] | [next] | [standalone]


#84154 — Function pointer size (was Re: nullptr is not 0)

FromVir Campestris <vir.campestris@invalid.invalid>
Date2022-05-17 21:30 +0100
SubjectFunction pointer size (was Re: nullptr is not 0)
Message-ID<t610ls$8r7$1@dont-email.me>
In reply to#84014
On 09/05/2022 22:56, Scott Lurndal wrote:
> Vir Campestris <vir.campestris@invalid.invalid> writes:
>> On 09/05/2022 06:06, Juha Nieminen wrote:
>>> Member function pointers shouldn't really be thought of as normal pointers.
>>> They are rather different beasts, behave differently in many respects, and
>>> you can't even convert from member-function-pointer to regular-pointer and
>>> back safely because they are completely incompatible with each other.
>>> They are likely not even the same size.
>>
>> _Likely_ not even the same size?
> 
> With g++ on linux, sizeof(member function pointer) returns
> 16 bytes.
> 

:O

I just experimented. Yes, it's 16 bytes, while an ordinary function 
pointer is only 8 (Linux 64, g++).

But the top 8 bytes always seem to be zero.

When are they anything else? Because if they aren't there's no reason 
for the different size.

Andy

[toc] | [prev] | [next] | [standalone]


#84155 — Re: Function pointer size (was Re: nullptr is not 0)

Fromscott@slp53.sl.home (Scott Lurndal)
Date2022-05-17 21:00 +0000
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<62UgK.19872$L_b6.6714@fx33.iad>
In reply to#84154
Vir Campestris <vir.campestris@invalid.invalid> writes:
>On 09/05/2022 22:56, Scott Lurndal wrote:
>> Vir Campestris <vir.campestris@invalid.invalid> writes:
>>> On 09/05/2022 06:06, Juha Nieminen wrote:
>>>> Member function pointers shouldn't really be thought of as normal pointers.
>>>> They are rather different beasts, behave differently in many respects, and
>>>> you can't even convert from member-function-pointer to regular-pointer and
>>>> back safely because they are completely incompatible with each other.
>>>> They are likely not even the same size.
>>>
>>> _Likely_ not even the same size?
>> 
>> With g++ on linux, sizeof(member function pointer) returns
>> 16 bytes.
>> 
>
>:O
>
>I just experimented. Yes, it's 16 bytes, while an ordinary function 
>pointer is only 8 (Linux 64, g++).
>
>But the top 8 bytes always seem to be zero.
>
>When are they anything else? Because if they aren't there's no reason 
>for the different size.

An offset is stored in the high bytes so that 'this' can be adjusted
in the thunk (that sets the implicit first parameter 'this' when calling
the function) when the function pointer refers to a virtual function
implemented in a derived class.

[toc] | [prev] | [next] | [standalone]


#84198 — Re: Function pointer size (was Re: nullptr is not 0)

FromVir Campestris <vir.campestris@invalid.invalid>
Date2022-05-19 21:52 +0100
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t66alp$lt9$1@dont-email.me>
In reply to#84155
On 17/05/2022 22:00, Scott Lurndal wrote:
>>
>> :O
>>
>> I just experimented. Yes, it's 16 bytes, while an ordinary function
>> pointer is only 8 (Linux 64, g++).
>>
>> But the top 8 bytes always seem to be zero.
>>
>> When are they anything else? Because if they aren't there's no reason
>> for the different size.
> 
> An offset is stored in the high bytes so that 'this' can be adjusted
> in the thunk (that sets the implicit first parameter 'this' when calling
> the function) when the function pointer refers to a virtual function
> implemented in a derived class.

OK thanks, I think I see.

(That's thanks to Scott, Andrey and Juha FTAOD.)

Andy

[toc] | [prev] | [next] | [standalone]


#84200 — Re: Function pointer size (was Re: nullptr is not 0)

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-05-19 14:08 -0700
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t66bjt$dg6$1@dont-email.me>
In reply to#84155
On 5/17/2022 2:00 PM, Scott Lurndal wrote:
> 
> An offset is stored in the high bytes so that 'this' can be adjusted
> in the thunk (that sets the implicit first parameter 'this' when calling
> the function) when the function pointer refers to a virtual function
> implemented in a derived class.

Again, virtuality of the target function has absolutely nothing to do 
with the matter. Mentioning it will only obfuscate the actual purpose of 
the upper word in the pointer.

The offset stored in the upper word is generally needed every time you 
call a [non-virtual] function in the `Derived` class through a `void 
(Base::*)()` pointer.

Here's the example again (note: no virtual functions)

   #include <cassert>
   #include <iostream>

   struct PaddingBase { char a[64]; };

   struct Base
   {
     int b = 2;
     void foo() { std::cout << b << std::endl; }
   };

   struct Derived : PaddingBase, Base
   {
     int d = 42;
     void bar() { std::cout << d << std::endl; }
   };

   void invoke(Base *b, void (Base::*pfb)())
   {
     (b->*pfb)();
   }

   int main()
   {
     void (Base::*pfb)() =
       static_cast<void (Base::*)()>(&Derived::bar);

     Derived d;
     Base *pb = &d;
     assert((void *) pb != (void *) &d);

     invoke(pb, pfb); // Properly calls `d.bar()`
   }

If you inspect the representation of `pfb` you will see that its upper 
word is non-zero in this example.

If you inspect the generated assembly code for `invoke` you will see how 
both parts of the pointer (upper word and lower word) are used in 
different compilers.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#84156 — Re: Function pointer size (was Re: nullptr is not 0)

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-05-17 17:05 -0700
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t61d8k$q22$1@dont-email.me>
In reply to#84154
On 5/17/2022 1:30 PM, Vir Campestris wrote:
> 
> When are they anything else? Because if they aren't there's no reason 
> for the different size.
> 

I provided an example sample in adjacent message in this thread. Pointer 
`pfb2` in that example will have non-zero offset stored in it.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#84158 — Re: Function pointer size (was Re: nullptr is not 0)

FromJuha Nieminen <nospam@thanks.invalid>
Date2022-05-18 04:46 +0000
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t61tn1$1gd6$1@gioia.aioe.org>
In reply to#84154
Vir Campestris <vir.campestris@invalid.invalid> wrote:
> I just experimented. Yes, it's 16 bytes, while an ordinary function 
> pointer is only 8 (Linux 64, g++).
> 
> But the top 8 bytes always seem to be zero.
> 
> When are they anything else? Because if they aren't there's no reason 
> for the different size.

If you have a reference or pointer to an object of type class A, and a
member pointer to a member function of class A, which is virtual, if
the actual object pointed to is of some derived type B which has its
own specialization of that virtual function, calling the function using
the pointer will call the derived implementation not, the one in class A.

For this to be possible the pointer to member function needs additional
data.

[toc] | [prev] | [next] | [standalone]


#84161 — Re: Function pointer size (was Re: nullptr is not 0)

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-05-18 02:14 -0700
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t62ddu$41b$1@dont-email.me>
In reply to#84158
On 5/17/2022 9:46 PM, Juha Nieminen wrote:
> Vir Campestris <vir.campestris@invalid.invalid> wrote:
>> I just experimented. Yes, it's 16 bytes, while an ordinary function
>> pointer is only 8 (Linux 64, g++).
>>
>> But the top 8 bytes always seem to be zero.
>>
>> When are they anything else? Because if they aren't there's no reason
>> for the different size.
> 
> If you have a reference or pointer to an object of type class A, and a
> member pointer to a member function of class A, which is virtual, if
> the actual object pointed to is of some derived type B which has its
> own specialization of that virtual function, calling the function using
> the pointer will call the derived implementation not, the one in class A.
> 
> For this to be possible the pointer to member function needs additional
> data.

No, that's incorrect.

This has nothing to do with virtual functions. On the contrary, 
pointers-to-virtual-functions are "easy": regular virtual call mechanism 
itself is already required to incorporate all necessary mechanics to 
properly invoke virtual functions across the entire hierarchy of 
classes. This mechanics is already present in "regular" virtual calls 
(without involving any pointers-to-members).

Pointers-to-members simply piggyback on that already existing 
functionality. For which reason pointers-to-virtual-functions in a 
traditional implementation do not need to store any extra info.

I have already provided exhaustive explanation for when this extra info 
is really needed: specifically for calls aimed at non-virtual functions, 
which are forced to implement "virtual-like" behavior.

-- 
Best regards,
Andrey



[toc] | [prev] | [next] | [standalone]


#84181 — Re: Function pointer size (was Re: nullptr is not 0)

FromJuha Nieminen <nospam@thanks.invalid>
Date2022-05-19 14:53 +0000
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t65lls$1nug$1@gioia.aioe.org>
In reply to#84161
Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
>> If you have a reference or pointer to an object of type class A, and a
>> member pointer to a member function of class A, which is virtual, if
>> the actual object pointed to is of some derived type B which has its
>> own specialization of that virtual function, calling the function using
>> the pointer will call the derived implementation not, the one in class A.
>> 
>> For this to be possible the pointer to member function needs additional
>> data.
> 
> No, that's incorrect.
> 
> This has nothing to do with virtual functions. On the contrary, 
> pointers-to-virtual-functions are "easy": regular virtual call mechanism 
> itself is already required to incorporate all necessary mechanics to 
> properly invoke virtual functions across the entire hierarchy of 
> classes. This mechanics is already present in "regular" virtual calls 
> (without involving any pointers-to-members).

I'm not sure that's correct.

When you have a pointer-to-member, in the location of the call the compiler
doesn't know *which* member function it's pointing to. It only knows its
signature, not its name. The class may have several differently-named
member fuctions with the same signature. I don't think the compiler can
even know (from the source code alone) if the pointed-to function is
virtual or not.

Thus, the compiler needs to create code that somehow figures out if
that member function is virtual, and which function it is, and then
use the vtable as normal to jump to the actual most-derived implementation.
I don't think it can do this without the extra data in the pointer.
(Well, I suppose it theoretically could, but that might require some
searching).

Please correct me if I'm wrong. (Honestly. This isn't sarcasm.)

[toc] | [prev] | [next] | [standalone]


#84184 — Re: Function pointer size (was Re: nullptr is not 0)

From"Alf P. Steinbach" <alf.p.steinbach@gmail.com>
Date2022-05-19 17:19 +0200
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t65n6s$ak9$1@dont-email.me>
In reply to#84181
On 19 May 2022 16:53, Juha Nieminen wrote:
> Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
>>> If you have a reference or pointer to an object of type class A, and a
>>> member pointer to a member function of class A, which is virtual, if
>>> the actual object pointed to is of some derived type B which has its
>>> own specialization of that virtual function, calling the function using
>>> the pointer will call the derived implementation not, the one in class A.
>>>
>>> For this to be possible the pointer to member function needs additional
>>> data.
>>
>> No, that's incorrect.
>>
>> This has nothing to do with virtual functions. On the contrary,
>> pointers-to-virtual-functions are "easy": regular virtual call mechanism
>> itself is already required to incorporate all necessary mechanics to
>> properly invoke virtual functions across the entire hierarchy of
>> classes. This mechanics is already present in "regular" virtual calls
>> (without involving any pointers-to-members).
> 
> I'm not sure that's correct.
> 
> When you have a pointer-to-member, in the location of the call the compiler
> doesn't know *which* member function it's pointing to. It only knows its
> signature, not its name. The class may have several differently-named
> member fuctions with the same signature. I don't think the compiler can
> even know (from the source code alone) if the pointed-to function is
> virtual or not.
> 
> Thus, the compiler needs to create code that somehow figures out if
> that member function is virtual, and which function it is, and then
> use the vtable as normal to jump to the actual most-derived implementation.
> I don't think it can do this without the extra data in the pointer.
> (Well, I suppose it theoretically could, but that might require some
> searching).
> 
> Please correct me if I'm wrong. (Honestly. This isn't sarcasm.)

Just an example of what you're saying:


#include <stdio.h>

struct A
{
     void foo() const { printf( "A::foo\n" ); }
     virtual void bar() const { printf( "A::bar\n" ); }
};

struct B: A
{
     void bar() const override { printf( "B::bar\n" ); }
};

auto main() -> int
{
     auto        f = &A::foo;
     const A&    o = B();

     f = &A::bar;
     (o.*f)();    // "B::bar"
}


Cheers,

- Alf

[toc] | [prev] | [next] | [standalone]


#84192 — Re: Function pointer size (was Re: nullptr is not 0)

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-05-19 10:14 -0700
SubjectRe: Function pointer size (was Re: nullptr is not 0)
Message-ID<t65ttj$kf5$1@dont-email.me>
In reply to#84184
On 5/19/2022 8:19 AM, Alf P. Steinbach wrote:
> On 19 May 2022 16:53, Juha Nieminen wrote:
>> Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
>>>> If you have a reference or pointer to an object of type class A, and a
>>>> member pointer to a member function of class A, which is virtual, if
>>>> the actual object pointed to is of some derived type B which has its
>>>> own specialization of that virtual function, calling the function using
>>>> the pointer will call the derived implementation not, the one in 
>>>> class A.
>>>>
>>>> For this to be possible the pointer to member function needs additional
>>>> data.
>>>
>>> No, that's incorrect.
>>>
>>> This has nothing to do with virtual functions. On the contrary,
>>> pointers-to-virtual-functions are "easy": regular virtual call mechanism
>>> itself is already required to incorporate all necessary mechanics to
>>> properly invoke virtual functions across the entire hierarchy of
>>> classes. This mechanics is already present in "regular" virtual calls
>>> (without involving any pointers-to-members).
>>
>> I'm not sure that's correct.
>>
>> When you have a pointer-to-member, in the location of the call the 
>> compiler
>> doesn't know *which* member function it's pointing to. It only knows its
>> signature, not its name. The class may have several differently-named
>> member fuctions with the same signature. I don't think the compiler can
>> even know (from the source code alone) if the pointed-to function is
>> virtual or not.
>>
>> Thus, the compiler needs to create code that somehow figures out if
>> that member function is virtual, and which function it is, and then
>> use the vtable as normal to jump to the actual most-derived 
>> implementation.
>> I don't think it can do this without the extra data in the pointer.
>> (Well, I suppose it theoretically could, but that might require some
>> searching).
>>
>> Please correct me if I'm wrong. (Honestly. This isn't sarcasm.)
> 
> Just an example of what you're saying:
> 
> 
> #include <stdio.h>
> 
> struct A
> {
>      void foo() const { printf( "A::foo\n" ); }
>      virtual void bar() const { printf( "A::bar\n" ); }
> };
> 
> struct B: A
> {
>      void bar() const override { printf( "B::bar\n" ); }
> };
> 
> auto main() -> int
> {
>      auto        f = &A::foo;
>      const A&    o = B();
> 
>      f = &A::bar;
>      (o.*f)();    // "B::bar"
> }
> 

Not sure what this is supposed to illustrate. That 
pointers-to-member-functions implement "late binding" at the point of 
the call? Yes, that's true and that's banal.

However, this still does not in any way mean that 
pointers-to-member-function has to distinguish between pointing to a 
"regular" function and pointing to a virtual function.

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c++


csiph-web