CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    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.

  2. #2
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by Lindley View Post
    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.

  3. #3
    Join Date
    May 2009
    Posts
    2,413

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by Lindley View Post
    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};
    };

  4. #4
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by nuzzle View Post
    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.

  5. #5
    Join Date
    May 2009
    Posts
    2,413

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by monarch_dodra View Post
    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.

  6. #6
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by nuzzle View Post
    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.

  7. #7
    Join Date
    May 2009
    Posts
    2,413

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by monarch_dodra View Post
    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.

  8. #8
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    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.

  9. #9
    Join Date
    Mar 2002
    Location
    Kent, United Kingdom
    Posts
    399

    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

  10. #10
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    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.

  11. #11
    Join Date
    Apr 2004
    Location
    England, Europe
    Posts
    2,492

    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.
    My hobby projects:
    www.rclsoftware.org.uk

  12. #12
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by Zaccheus View Post
    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.

  13. #13
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by Lindley View Post
    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

  14. #14
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Automatically obtaining the address of another member of the same object

    Quote Originally Posted by D_Drmmr View Post
    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.

  15. #15
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Automatically obtaining the address of another member of the same object

    That's a good idea.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured