Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Difference between pointer to the no data member and the pointer tothe first member

Reply
Thread Tools

Difference between pointer to the no data member and the pointer tothe first member

 
 
somenath
Guest
Posts: n/a
 
      06-30-2013


I am trying to understanding the difference between the pointer to the no data member and pointer to the first member of class.

Also I have learned that “The value returned from taking the member’s address, however, is always bumped up by 1”.
To understand this concept I wrote the following simple program.

#include<iostream>
using namespace std;
class A
{
public:
int data;
int data2;

};

int main(void)
{

A a1;
int A::*first_data_member =&A::data;
int A::*second_data_member =&A::data2;
int A::*no_data_member ;
cout<<"no_data_member = "<<(no_data_member)<<endl;
cout<<"first_data_member = "<<(first_data_member)<<endl;
cout<<"second_data_member = "<<(second_data_member)<<endl;


return 0;

}

The output of the above program is as follows.
=================================================
no_data_member = 1
first_data_member = 1
second_data_member = 1

================================================

I am not able to understand the output of the program.

My expectation is if no_data_member is 1 then first_data_member sould be = no_data_member + 1 and second_data_member should be = first_data_member +1.

Please let me know where I am going wrong?



 
Reply With Quote
 
 
 
 
Öö Tiib
Guest
Posts: n/a
 
      06-30-2013
On Sunday, 30 June 2013 19:25:24 UTC+3, somenath wrote:
> I am trying to understanding the difference between the pointer to the
> no data member and pointer to the first member of class.
>
> Also I have learned that “The value returned from taking the
> member’s address, however, is always bumped up by 1”.


What book that was? By your code it seems that you are confused
and trying things out by trial and error without understanding
their purpose. What you try to program should (I am even not
sure) perhaps to look like that:

#include<iostream>
class A
{
public:
int data;
int data2;
};

int main()
{
A a1;
int* first_data_member =&a1.data;
int* second_data_member =&a1.data2;
int* no_data_member = NULL;
std::cout<<"no_data_member = "<<no_data_member<<std::endl;
std::cout<<"first_data_member = "<<first_data_member<<std::endl;
std::cout<<"second_data_member = "<<second_data_member<<std::endl;
}

The output of the above program is as follows.
=================================================
no_data_member = 0
first_data_member = 0xbf876138
second_data_member = 0xbf87613c

Hope it helps.
 
Reply With Quote
 
 
 
 
somenath
Guest
Posts: n/a
 
      07-01-2013
On Sunday, June 30, 2013 11:30:33 PM UTC+5:30, Öö Tiib wrote:
> On Sunday, 30 June 2013 19:25:24 UTC+3, somenath wrote:
>
> > I am trying to understanding the difference between the pointer to the

>
> > no data member and pointer to the first member of class.

>
> >

>
> > Also I have learned that “The value returned from taking the

>
> > member’s address, however, is always bumped up by 1”.

>
>
>
> What book that was? By your code it seems that you are confused
>
> and trying things out by trial and error without understanding
>
> their purpose. What you try to program should (I am even not
>
> sure) perhaps to look like that:
>


The book is "Inside the C++ Object Model". Actually I am trying to understand the possible layout of the pointer to the data member. In this book it is said that "The value returned from taking the member’s address, however, is always bumped up by 1." . Also trying to understand how compiler solve the problem of " distinguishing between a pointer to no data member and apointer to the first data member."

For this I was trying to create an example which will have a pointer to theno member of class and first and second member of the class . So that I can understand the layout of those pointer. But I think I have failed to do that.

I the book the example given is as follows
///Beginning of example
class Point3d {
public:
virtual ~Point3d();
// ...
protected:
static Point3d origin;
float x, y, z;
};

float Point3d::*p1 = 0;
float Point3d::*p2 = &Point3d:;

// oops: how to distinguish?
if ( p1 == p2 ) {
cout << ” p1 & p2 contain the same value — ”;
cout << ” they must address the same member!” << endl;
}

To distinguish between p1 and p2, each actual member offset value is bumpedup by 1. Hence, both the compiler (and the user) must remember to subtract1 before actually using the value to address a member. "

//End of example


>
> #include<iostream>
>
> class A
>
> {
>
> public:
>
> int data;
>
> int data2;
>
> };
>
>
>
> int main()
>
> {
>
> A a1;
>
> int* first_data_member =&a1.data;
>
> int* second_data_member =&a1.data2;
>
> int* no_data_member = NULL;
>
> std::cout<<"no_data_member = "<<no_data_member<<std::endl;
>
> std::cout<<"first_data_member = "<<first_data_member<<std::endl;
>
> std::cout<<"second_data_member = "<<second_data_member<<std::endl;
>
> }


So my question is then how can we understand the fact that
"The value returned from taking the member’s address, however, is always bumped up by 1"
>
> The output of the above program is as follows.
>
> =================================================
>
> no_data_member = 0
>
> first_data_member = 0xbf876138
>
> second_data_member = 0xbf87613c
>
>
>
> Hope it helps.

 
Reply With Quote
 
somenath
Guest
Posts: n/a
 
      07-01-2013
On Sunday, June 30, 2013 11:49:20 PM UTC+5:30, Paavo Helde wrote:
> Paavo Helde wrote in
>
>
>
> >> I am trying to understanding the difference between the pointer to

>
> >> the no data member and pointer to the first member of class.

>
>
>
> I started to wonder myself how the data member pointers are encoded, and
>
> adapted your program to the following:
>
>
>
> #include<iostream>
>
> #include <stdint.h>
>
> using namespace std;
>
>
>
> class A
>
> {
>
> public:
>
> int data;
>
> int data2;
>
>
>
> };
>
>
>
> int main(void)
>
> {
>
> int A::*first_data_member =&A::data;
>
> int A::*second_data_member =&A::data2;
>
> int A::*no_data_member = NULL;
>
>
>
> if (sizeof(int A::*)==4) {
>
> int32_t x;
>
>
>
> memcpy(&x, &no_data_member, 4);
>
> cout<<"no_data_member = "<< x <<endl;
>
>
>
> memcpy(&x, &first_data_member, 4);
>
> cout<<"first_data_member = "<< x <<endl;
>
>
>
> memcpy(&x, &second_data_member, 4);
>
> cout<<"second_data_member = "<< x <<endl;
>
> }
>
> }
>
>
>
> The output is with my compiler:
>
>
>
> no_data_member = -1
>
> first_data_member = 0
>
> second_data_member = 4
>
>
>
> So it appears a NULL data member pointer is encoded by integer value -1
>
> and otherwise they just store byte offset of the data member inside the
>
> object. But this is all implementation-specific so one must not rely on
>
> this.


I am not getting why are you using memcpy in the above program? Also could you please explain the meaning "So it appears a NULL data member pointer isencoded by integer value -1 and otherwise they just store byte offset of the data member inside the object"
Does it mean that the pointer to the no member value is -1 and pointer thefirst member is 0 in this case? What exactly the meaning of "encoded" here?

 
Reply With Quote
 
Öö Tiib
Guest
Posts: n/a
 
      07-01-2013
On Monday, 1 July 2013 03:13:52 UTC+3, somenath wrote:
> Actually I am trying to understand the possible layout of the pointer
> to the data member.


It is not specified by standard to leave free hands to compiler writers.
You can have "no member" with all bits set and no bumping of others.
You can have "no member" equal with 0 and all others bumped up by 1.

Paavo Helde understood what you attempt better than me. If you want to
see what is inside of something do like he did. memcpy the contents
to suitable integer (or into array of bytes) and output that.
Paavo used signed integer so the "no member" value that on his compiler
had all bits set was displayed as "-1".

Sending the pointer to member to cout seems to result with "1"
when the pointer points at member and with "0" when it is initialized
with 0. Since you had your "no_data_member" uninitialized it is
very unlikely that it had that special "no member" value and so
it displayed "1" too.

> In this book it is said that "The value returned from taking the
> member’s address, however, is always bumped up by 1.".


The book describes specific implementation; it may be so but
there are no guarantees anywhere.

> Also trying to understand how compiler solve the problem of
> " distinguishing between a pointer to no data member and a pointer to
> the first data member."


Such knowledge can be useful if you want to make some platform-specific
debugging tool but generally you should avoid to write code that relies
on it. Using undefined features without very good reason and
abundant commentary in code may even get your work contract terminated.
 
Reply With Quote
 
Kalle Olavi Niemitalo
Guest
Posts: n/a
 
      07-01-2013
Richard Damon <(E-Mail Removed)> writes:

> To throw another kink into the problem, a simple offset is NOT
> sufficient for a fully generalized member pointer.


The "Itanium C++ ABI" used by GCC on multiple platforms
<http://refspecs.linuxfoundation.org/cxxabi-1.86.html#member-pointers>
says a pointer to data member is just an offset; there is no provision
for virtual bases.

Conversion of a pointer to data member across a virtual base
seems disallowed by [conv.mem] and [expr.cast] anyway, so I don't
think your sample code is valid C++:

> int derived::* p1 = &base::b2;


According to [expr.unary.op], the type of &base::b2 is "int base::*".
The result then cannot be converted to "int derived::*".

I'm not sure whether the rules are any different for pointers to
member functions.
 
Reply With Quote
 
Kalle Olavi Niemitalo
Guest
Posts: n/a
 
      07-01-2013
Richard Damon <(E-Mail Removed)> writes:

> It looks like perhaps the line should be
>
> int derived::* p1 = &derived::b2;


Because class derived inherits int b2 from class base, the type
of &derived::b2 is "int base::*", just like &base::b2.
An example in [expr.unary.op] demonstrates exactly this.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      07-02-2013
On Sunday, 30 June 2013 19:00:33 UTC+1, Öö Tiib wrote:
> On Sunday, 30 June 2013 19:25:24 UTC+3, somenath wrote:
> > I am trying to understanding the difference between the pointer to the
> > no data member and pointer to the first member of class.


> > Also I have learned that “The value returned from taking the
> > member’s address, however, is always bumped up by 1”.


> What book that was? By your code it seems that you are confused
> and trying things out by trial and error without understanding
> their purpose. What you try to program should (I am even not
> sure) perhaps to look like that:


> #include<iostream>
> class A
> {
> public:
> int data;
> int data2;
> };


> int main()
> {
> A a1;
> int* first_data_member =&a1.data;
> int* second_data_member =&a1.data2;
> int* no_data_member = NULL;
> std::cout<<"no_data_member = "<<no_data_member<<std::endl;
> std::cout<<"first_data_member = "<<first_data_member<<std::endl;
> std::cout<<"second_data_member = "<<second_data_member<<std::endl;
> }


> The output of the above program is as follows.
> =================================================
> no_data_member = 0
> first_data_member = 0xbf876138
> second_data_member = 0xbf87613c


> Hope it helps.


His code used pointers to members, which are completely
different. (The expression "no data member" is a bit strange,
but it looks like he meant null pointers.)

--
James

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      07-02-2013
On Sunday, 30 June 2013 17:25:24 UTC+1, somenath wrote:
> I am trying to understanding the difference between the
> pointer to the no data member and pointer to the first member
> of class.


By "no data member", I presume you mean a null pointer (of type
pointer to member).

> Also I have learned that “The value returned from taking the
> member’s address, however, is always bumped up by 1”.


That's the usual implementation, but it certainly isn't
required. An implementation could also use -1 as the
representation for null pointers when they are pointers to
(non-function) member.

> To understand this concept I wrote the following simple program.


> #include<iostream>


> using namespace std;
> class A
> {
> public:
> int data;
> int data2;
> };


> int main(void)
> {
> A a1;
> int A::*first_data_member =&A::data;
> int A::*second_data_member =&A::data2;
> int A::*no_data_member ;
> cout<<"no_data_member = "<<(no_data_member)<<endl;
> cout<<"first_data_member = "<<(first_data_member)<<endl;
> cout<<"second_data_member = "<<(second_data_member)<<endl;
> return 0;
> }


> The output of the above program is as follows.
> =================================================
> no_data_member = 1
> first_data_member = 1
> second_data_member = 1
> ================================================


> I am not able to understand the output of the program.


I am. But I can understand your surprize for the last entry.

> My expectation is if no_data_member is 1 then
> first_data_member sould be = no_data_member + 1 and
> second_data_member should be = first_data_member +1.


> Please let me know where I am going wrong?


Two things. The first is that you never initialize
no_data_member, so using it is undefined behavior. In this
case, what's happening is that it contains random junk (which
isn't 0). You should define it as:

int A::*no_data_member = NULL; // or nullptr, if you have C++11

The second is that there isn't an overload of << for outputting
pointers to members. So the compiler tries to find a conversion
for which there is an overload. For horrible historical
reasons, pointers (including pointers to members) convert to
bool, and there is a << defined for bool, so what you're seeing
is the default output for each of the pointers defined as
a bool.

Formally, for this sort of thing, you should be dumping the
pointers using something along the lines of:

template <typename T>
class Dump
{
T const& myObj;
public:
Dump( T const& obj ) : myObj( obj ) {}
std:stream& operator<<( std:stream& dest, Dump const& obj )
{
IOSave stateSaver( dest ); // Saves fmtflags, etc.
dest.setf( std::ios_base::hex, std::ios_base::baseflags );
dest.fill( '0' );
unsigned char const* begin
= reinterpret_cast<unsigned char const*>( &obj.myObj );
unsigned char const* end = begin + sizeof( T );;
for ( char const* current = begin; current != end; ++ current ) {
if ( current != begin ) {
dest << ' ';
}
dest << std::setw(2) << *current;
}
return dest;
}
};

template <typename T>
Dump<T>
dump( T const& obj )
{
return Dump<T>( obj );
}

You can then do things like:

std::cout << "no data member = " << dump( no_data_member ) << std::endl;

and get a hex dump of the values.

This is a generic solution for looking at the representation of
any type, and should be generally useful if you're trying to
figure out what the compiler is doing. Depending on what you
are looking at, you may want to modify it to dump the data as
unsigned or size_t, rather than as bytes. Or in specific cases
(like this one, perhaps), you might want to cast the pointer to
an appropriately sized unsigned integer, and use it. (Pointers
to data members are almost always implemented as an integral
type under the hood.)

--
James
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      07-02-2013
On Monday, 1 July 2013 01:13:52 UTC+1, somenath wrote:
> On Sunday, June 30, 2013 11:30:33 PM UTC+5:30, Öö Tiib wrote:


> > On Sunday, 30 June 2013 19:25:24 UTC+3, somenath wrote:
> > > I am trying to understanding the difference between the pointer to the
> > > no data member and pointer to the first member of class.


> > > Also I have learned that “The value returned from taking the
> > > member’s address, however, is always bumped up by 1”.


> > What book that was? By your code it seems that you are confused
> > and trying things out by trial and error without understanding
> > their purpose. What you try to program should (I am even not
> > sure) perhaps to look like that:


> The book is "Inside the C++ Object Model".


This book describes one possible way of implementing C++. In
the case of pointers to data members, I think the solution he
describes is almost univeral (but I'm not sure), but for other
things, there is a lot of variance.

> Actually I am trying to understand the possible layout of the
> pointer to the data member.


Typically, it's just an int under the hood.

> In this book it is said that "The value returned
> from taking the member’s address, however, is always bumped up
> by 1." . Also trying to understand how compiler solve the
> problem of " distinguishing between a pointer to no data
> member and a pointer to the first data member."


You just answered your question. The int value in a null
pointer to member will be 0. Otherwise, the int value will be
the physical offset of the member in the class, incremented by
one to ensure that it can never be 0.

> For this I was trying to create an example which will have
> a pointer to the no member of class and first and second
> member of the class . So that I can understand the layout of
> those pointer. But I think I have failed to do that.


> I the book the example given is as follows


> ///Beginning of example


> class Point3d {
> public:
> virtual ~Point3d();
> // ...
> protected:
> static Point3d origin;
> float x, y, z;
> };


> float Point3d::*p1 = 0;
> float Point3d::*p2 = &Point3d:;


> // oops: how to distinguish?
> if ( p1 == p2 ) {
> cout << ” p1 & p2 contain the same value — ”;
> cout << ” they must address the same member!” << endl;
> }


This is a bad example for two reasons. First, it shouldn't
compile, because the members whose address you are taking are
protected (and you're not in a derived class). Second, the
class has a virtual function, which means that it will have
(typically) a vptr at the start address. So even without
incrementing the value, &Point3d: will not be 0.

> To distinguish between p1 and p2, each actual member offset
> value is bumped up by 1. Hence, both the compiler (and the
> user) must remember to subtract 1 before actually using the
> value to address a member. "


The user doesn't have to remember anything. The compiler takes
care of everything.

> //End of example


--
James
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can read in the BMP data correctly ,but the size is not right? Jimmie He Python 5 05-04-2013 10:26 AM
Is there a difference between the use of the word montage vscollage Danny D. Digital Photography 8 04-15-2013 02:24 PM
pointer-to-member data and pointer-to-member functions and access specifiers Stephen Howe C++ 2 11-06-2012 12:32 PM
Difference between struct and class and pointer to member data Pep C++ 4 09-10-2009 09:35 AM
Difference between bin and obj directories and difference between project references and dll references jakk ASP .Net 4 03-22-2005 09:23 PM



Advertisments