Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
997 views
in Technique[技术] by (71.8m points)

c++ - Using offsetof() to get owner object from member variable

I would like to implement 'GetParent()' function in here-

class ChildClass;

class ParentClass
{
public:
    ....
    ChildClass childObj;
    ....
};

class ChildClass
{
    friend class ParentClass;
private:
    ChildClass();

public:
    ParentClass* GetParent();
};

I've tried to create a private member variable which stores pointer to parent object. However this method requires additional memory.

class ChildClass
{
    friend class ParentClass;

private:
    ChildClass();

    ParentClass* m_parent;

public:
    ParentClass* GetParent()
    {
        return m_parent;
    }
};

So I used offsetof() macro (performance costs of calling offsetof() can be ignored), but I'm not sure this approach is safe. Would it be work on every situation? Is there any better Idea?

class ChildClass
{
public:
    ParentClass* GetParent()
    {
        return reinterpret_cast<ParentClass*>(
            reinterpret_cast<int8_t*>(this) - offsetof(ParentClass, childObj)
            );
    }
};
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Calculating the address of the container object using offsetof is safe in the sense that it can work. offsetof is commonly used in C for this purpose. See for example the container_of macro in Linux kernel.

It can be unsafe in the sense that if there is a ChildClass instance that is not that particular member variable, then you have undefined behaviour on your hands. Of course, since the constructor is private, you should be able to prevent that.

Another reason why it's not safe is that it has undefined behaviour if the container type is not a standard layout type.

So, it can work as long as you take the caveats into account. Your implementation however, is broken. The second parameter of the offsetof macro must be the name of the member. In this case, it must be childObj and not e[index] which is not the name of the member.

Also (maybe someone will correct me if I'm wrong, but I think) casting to an unrelated type uint8_t* before doing the pointer arithmetic and then cast to yet another unrelated type seems a bit dangerous. I recommend using char* as the intermediate type. It is guaranteed that sizeof(char) == 1 and it has special exceptions about aliasing and not having trap representations.

It might be worth mentioning that this use - or any use other than use with arrays - of pointer arithmetic is not defined by the standard. Which strictly speaking makes offsetof useless. Still, pointers are widely used beyond arrays, so the lack of standard backing can in this case be ignored.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...