-
October 26th, 2010, 11:37 AM
#1
Automatically obtaining the address of another member of the same object
Let's say I create an object:
Code:
template <typename T>
struct RelativeLoc
{
ptrdiff_t offset;
RelativeLoc(T* other)
{
offset = reinterpret_cast<const char*>(other) - reinterpret_cast<char*>(this);
}
T* getOtherAddr() const
{
return reinterpret_cast<T*>(reinterpret_cast<const char*>(this) + offset);
}
}
And then put this in an object:
Code:
struct MyClass
{
std::vector<short> stuff;
RelativeLoc<std::vector<short>> relative;
MyClass(): relative(&stuff);
};
Is this safe?
The goal here is to have some other object in MyClass which always needs a reference to the "stuff" in the same object. I'd like to develop a way of automatically updating this on copies/moves which doesn't require writing an entire copy constructor for MyClass. If I can fill RelativeLoc with callbacks or something, it would fit the bill.
-
October 27th, 2010, 01:30 AM
#2
Re: Automatically obtaining the address of another member of the same object
Originally Posted by Lindley
Let's say I create an object:
Code:
template <typename T>
struct RelativeLoc
{
ptrdiff_t offset;
RelativeLoc(T* other)
{
offset = reinterpret_cast<const char*>(other) - reinterpret_cast<char*>(this);
}
T* getOtherAddr() const
{
return reinterpret_cast<T*>(reinterpret_cast<const char*>(this) + offset);
}
}
And then put this in an object:
Code:
struct MyClass
{
std::vector<short> stuff;
RelativeLoc<std::vector<short>> relative;
MyClass(): relative(&stuff);
};
Is this safe?
The goal here is to have some other object in MyClass which always needs a reference to the "stuff" in the same object. I'd like to develop a way of automatically updating this on copies/moves which doesn't require writing an entire copy constructor for MyClass. If I can fill RelativeLoc with callbacks or something, it would fit the bill.
As long as relative and stuff are in the same struct (or struct hierarchy), than that code seems perfectly safe to me.
As long as you use RelativeLoc in the way described here, both the default constructor and assignement operator should be fine. Heck, I'd consider making offset a const member, and re-defining the assignment operator as do nothing.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
October 27th, 2010, 03:30 AM
#3
Re: Automatically obtaining the address of another member of the same object
Originally Posted by Lindley
Is this safe?
In my view the fact that you have to ask this question indicates the construct should be avoided.
Maybe I'm missing something but if you want a pointer to stuff why don't you just use &stuff like,
Code:
struct MyClass
{
std::vector<short> stuff;
std::vector<short>* stuff_ptr() {return &stuff};
};
-
October 27th, 2010, 04:12 AM
#4
Re: Automatically obtaining the address of another member of the same object
Originally Posted by nuzzle
In my view the fact that you have to ask this question indicates the construct should be avoided.
Maybe I'm missing something but if you want a pointer to stuff why don't you just use &stuff like,
Code:
struct MyClass
{
std::vector<short> stuff;
std::vector<short>* stuff_ptr() {return &stuff};
};
That was my first reaction, but this doesn't work. The reason is that when you copy MyClass, you want the new stuff_ptr to point to the new stuff. The only way to do that is to give the address of stuff to the stuff_ptr, and hence, requires writing a copy constructor. By having the "Reference" keep an offset, you don't need to write a copy constructor, since the offset is the same for all instances of MyClass.
What lindley wrote seemed fishy to me at first, but it works. I'm more curious about why you would want suf a construct to begin with, and if this construct would work with his need.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
October 27th, 2010, 04:34 AM
#5
Re: Automatically obtaining the address of another member of the same object
Originally Posted by monarch_dodra
That was my first reaction, but this doesn't work.
It sure works. The stuff_ptr() function will always return a pointer to stuff of the current object.
What you cannot do is assign stuff_ptr() to an object variable and then copy the object. Then the variable of the copy will point to stuff of the object it was copied from. So you must always access stuff via a call to stuff_ptr() and never store a pointer to stuff in an object variable. But the same goes for Lindley's getOtherAddr() function so there's no difference really. Lindley's suggestion is just more complicated, more convoluted and more error prone due to ugly pointer arithmetics and not typesafe casts. In short exactly the kind of coding one should avoid.
Last edited by nuzzle; October 27th, 2010 at 05:01 AM.
-
October 27th, 2010, 04:49 AM
#6
Re: Automatically obtaining the address of another member of the same object
Originally Posted by nuzzle
It sure works. The stuff_ptr() function will always return a pointer to stuff of the current object.
What you cannot do is assign stuff_ptr() to an object variable and then copy the object. Then the variable in the copy will point to stuff of the object it was copied from. So you must always access stuff via a call to stuff_ptr() and never store a pointer to stuff in an object variable. But the same goes for Lindley's getOtherAddr() function so there's no difference really. Lindley's suggestion is just more complicated.
I missread your code, sorry. I though stuff_ptr was actually a member variable initialized to stuff. Didn't see it was actually a function.
I'm still not sure what Lindley is trying to do, so I can't judge either approach.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
October 27th, 2010, 05:41 AM
#7
Re: Automatically obtaining the address of another member of the same object
Originally Posted by monarch_dodra
I'm still not sure what Lindley is trying to do, so I can't judge either approach.
Well, judging only by what he's done it's the kind of mess that has given C++ a bad reputation and paved the way for "safe" languages such as Java.
-
October 27th, 2010, 06:59 AM
#8
Re: Automatically obtaining the address of another member of the same object
I'm trying to use libkdtree++ to optimize a program. However, I don't want to take the space to put the actual objects into the KDTree----instead I want to put indexes in and provide the tree with a dimension accessor that applies the indexes to the vector.
This is all fine so long as the underlying vector doesn't move. But if the object containing both the KDTree and the vector is copied or moved, then I have a problem----the KDTree's accessor is no longer valid.
While the KDTree does not allow its accessor to be modified for understandable reasons, I *can* copy-construct another one with a different accessor. It's probably a waste of cycles since the tree structure is already known, but I'll accept that.
The query is, can I update the pointer without having to write cctor, mctor, and operator= (both versions) for the enclosing object? There are unrelated fields in there too.
Another possible solution besides the above would be to wrap up the vector and the KDTree in a smaller object and give this object and operator[] which makes it behave as a vector, as well as the appropriate KDTree functions.
-
October 27th, 2010, 10:22 AM
#9
Re: Automatically obtaining the address of another member of the same object
Wouldn't it be easier to pass a reference to stuff into the object requiring access to stuff ?
I think the address of a reference the same as the address of what it refers to - if so, would this work ?
Code:
template <typename T>
struct RelativeLoc
{
T& other_ ;
RelativeLoc(T& other) :other_(other)
{
}
T* getOtherAddr() const
{
return &other_ ;
}
}
Code:
struct MyClass
{
std::vector<short> stuff;
RelativeLoc<std::vector<short>> relative;
MyClass(): relative(stuff);
};
your humble savant
-
October 27th, 2010, 10:25 AM
#10
Re: Automatically obtaining the address of another member of the same object
No, because when the RelativeLoc object is copied (within the copy of the surrounding object), it would still have the reference to the previous other object, not the new one.
-
October 27th, 2010, 11:25 AM
#11
Re: Automatically obtaining the address of another member of the same object
I'm still not clear what exactly are you trying to achieve, can you show us an actual example?
Just an observation:
When you copy an object, the address of the data member never changes.
Code:
void f()
{
C1 c1;
C2 c2;
c1=c2;
}
Only the values within the data members are manipulated, but nothing is actually moved around. Granted, if you re-allocate a vector then the addresses will change. As monarch_dodra implied the offset will be the same for every object. There must be a simpler way of doing this.
Last edited by Zaccheus; October 27th, 2010 at 11:31 AM.
-
October 27th, 2010, 12:56 PM
#12
Re: Automatically obtaining the address of another member of the same object
Originally Posted by Zaccheus
There must be a simpler way of doing this.
Sure----just implement the copy constructor. I'm just playing around with ideas for alternatives in the case when *most* of the object doesn't need special copy treatment.
I'm still not clear what exactly are you trying to achieve, can you show us an actual example?
Code:
vector<double> actualvals;
struct CmpInds
{
vector<double> *vals;
CmpInds(vector<double> &vals_): vals(&vals_) {}
bool operator<(int i1, int i2) const
{ return (*vals)[i1] < (*vals)[i2]; }
};
struct Sorted
{
vector<int> inds;
CmpInds cmp;
Sorted(vector<double> &actualvals):
inds(boost::counting_iterator(0),boost::counting_iterator(actualvals.size())),
cmp(CmpInds(actualvals))
{
sort(inds.begin(), inds.end(), cmp);
}
};
This is the basic idea, except with a simple sort rather than a KDTree, and only 1-D data (doubles). Now, put the Sorted object into another object alongside the actualvals:
Code:
struct Object
{
vector<double> vals;
Sorted srt;
Object(): srt(vals) {}
}
Now, what do you do to make sure srt remains valid when an Object is copied?
Assume that Sorted has some additional query functions which require the use of cmp.
-
October 28th, 2010, 05:04 AM
#13
Re: Automatically obtaining the address of another member of the same object
Originally Posted by Lindley
Is this safe?
In general, I don't think it is safe. In practice, I think it is safe as long as the two objects are stored in the same struct/class (i.e. not class hierarchy).
The construct is very similar to the C macro offsetof, which is only supported in C++ for POD types. Here's a thread about why it is, in principal, not safe to use offsetof on non-POD types.
What you are doing seems even safer than offsetof, because you are not relying on compile time offsets, but only that the offset between two member variables in a struct/class is equal for every instance of that struct/class. Though I don't think that's guaranteed by the standard, I would expect that to be true for 99.9% of the C++ compilers out there.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
October 28th, 2010, 07:34 AM
#14
Re: Automatically obtaining the address of another member of the same object
Originally Posted by D_Drmmr
What you are doing seems even safer than offsetof, because you are not relying on compile time offsets, but only that the offset between two member variables in a struct/class is equal for every instance of that struct/class. Though I don't think that's guaranteed by the standard, I would expect that to be true for 99.9% of the C++ compilers out there.
I don't know what the standard says, but it would seem odd to me iff every object of a class did not have the same memory layout. How would you reference the attributes of that object?
-----
Back to the subject: Your first provided implementation looks safe to me, provided you use it as described of course. I'd consider some tweaking though. For starters, I think the constructor should take a reference, and not a pointer. This would save you from ever constructing a RelativeLoc from a nullptr.
Also, instead of giving a getOtherAddr function, just give your class a pointer interface. Something like this:
Code:
#include <iostream>
#include <string>
template<typename T>
class RelativeLoc
{
public:
RelativeLoc(T& iOther) : offset(reinterpret_cast<const char*>(&iOther) - reinterpret_cast<const char*>(this))
{}
RelativeLoc(const RelativeLoc& iOther) : offset(iOther.offset)
{}
RelativeLoc& operator=(RelativeLoc iOther)
{return *this;}
T& operator*()
{
return *(operator T*());
}
T* operator->()
{
return operator T*();
}
operator T*()
{
return reinterpret_cast<T*>(reinterpret_cast<char*>(this) + offset);
}
private:
const ptrdiff_t offset;
};
int main()
{
//abusive use of RelativeLoc
std::string s = "hello!";
RelativeLoc<std::string> rl(s);
std::cout << *rl << std::endl;
std::cout << rl->c_str() << std::endl;
}
It just needs some extra tweaking for const correctness...
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
October 28th, 2010, 08:07 AM
#15
Re: Automatically obtaining the address of another member of the same object
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|