positions of attributes

Discussion in 'C++' started by Axel F, Jan 10, 2006.

  1. Axel F

    Axel F Guest

    Hi,

    I have question about the following.
    For instance I have a class like

    class Cvec3
    {
    public:
    float* begin() { return &x; }
    operator float*() { return &x; }
    public:
    float x,y,z;
    };

    and I want to use c-function which take a pointer to float like some gl
    functions. So I have defined the function begin(). I know this works and I
    had never problems with this.
    Somebody of my team says now, that it is not secure to do this, cause the
    compiler can reorder the members x,y,z or can change pack alignment. He says
    that nothing can be found about this in the c++ standard.

    I hope somebody can help me to get the right arguments.

    Thanks in advance,
    Axel
     
    Axel F, Jan 10, 2006
    #1
    1. Advertising

  2. Axel F

    Ben Pope Guest

    Axel F wrote:
    > Hi,
    >
    > I have question about the following.
    > For instance I have a class like
    >
    > class Cvec3
    > {
    > public:
    > float* begin() { return &x; }
    > operator float*() { return &x; }
    > public:
    > float x,y,z;
    > };
    >
    > and I want to use c-function which take a pointer to float like some gl
    > functions. So I have defined the function begin(). I know this works and I
    > had never problems with this.


    OK.

    > Somebody of my team says now, that it is not secure to do this, cause the
    > compiler can reorder the members x,y,z or can change pack alignment. He says
    > that nothing can be found about this in the c++ standard.


    I'm not sure how that would be relevant.

    > I hope somebody can help me to get the right arguments.


    How do you intend to use these functions? (I've modified your code
    slightly, but not in any way that changes the problem)

    #include <iostream>

    class Cvec3 {
    public:
    Cvec3() : x(1.1), y(1.2), z(1.3) {}; // Initialise members
    float* begin() { return &x; }
    operator float*() { return &x; }
    private:
    float x,y,z;
    };

    // ok, not a real C function, but close enough
    void myCFunc(float* f) {
    std::cout << *f << std::endl;
    }

    int main() {
    Cvec3 v;
    myCFunc(v.begin());
    myCFunc(v);
    }

    There's absolutely nothing wrong with that, providing v exists for at
    least as long as myCFunc requires it to.

    Ben Pope
    --
    I'm not just a number. To many, I'm known as a string...
     
    Ben Pope, Jan 10, 2006
    #2
    1. Advertising

  3. Axel F

    Jerry Coffin Guest

    Axel F wrote:
    > Hi,
    >
    > I have question about the following.
    > For instance I have a class like
    >
    > class Cvec3
    > {
    > public:
    > float* begin() { return &x; }
    > operator float*() { return &x; }
    > public:
    > float x,y,z;
    > };
    >
    > and I want to use c-function which take a pointer to float like some gl
    > functions. So I have defined the function begin(). I know this works and I
    > had never problems with this.
    > Somebody of my team says now, that it is not secure to do this, cause the
    > compiler can reorder the members x,y,z or can change pack alignment.


    If you're using this as I expect you are, he's basically right. My
    guess is that you're using begin as a pointer not just to x, but also
    to y and z For example, indexing off of the pointer it returns and
    treating x, y and z as a vector. You can fix part of the problem fairly
    easily, but not all of it. If you use:

    struct Cvec3 {
    float *begin() { return &x; }
    operator float*() { return &x; }

    float x, y, z;
    };

    This fixes some of the problems -- the compiler can no longer reorder
    the data, but it can still insert padding between x, y and Z. If you
    want to fix this, things get a bit more complex:

    struct Cvec3 {
    float *begin() { return &x; }
    operator float*() { return &x; }

    float data[3];

    float &x, &y, &z;

    Cvec3() : x(data[0]), y(data[1]), z(data[2]) {}
    };

    Now the three floats are guaranteed to be stored contiguously -- i.e.
    the compiler can't insert any padding between them. The x, y and z are
    just references to the three locations in data, so it makes basically
    no diference whether you use data[1] or y -- the two are basically just
    two ways of referring to the same thing.

    --
    Later,
    Jerry.





    He says
    > that nothing can be found about this in the c++ standard.
     
    Jerry Coffin, Jan 10, 2006
    #3
  4. Axel F

    Axel F Guest

    > If you're using this as I expect you are, he's basically right. My
    > guess is that you're using begin as a pointer not just to x, but also
    > to y and z For example, indexing off of the pointer it returns and
    > treating x, y and z as a vector. You can fix part of the problem fairly
    > easily, but not all of it. If you use:
    >
    > struct Cvec3 {
    > float *begin() { return &x; }
    > operator float*() { return &x; }
    >
    > float x, y, z;
    > };
    >
    > This fixes some of the problems -- the compiler can no longer reorder
    > the data, but it can still insert padding between x, y and Z. If you
    > want to fix this, things get a bit more complex:


    Thank you for your answer.
    the padding seems to be no problem, cause x,y,z are of the same type
    (4-byte), so that all elements are placed serial in memory also if I use
    8-byte alignment. And if I allocate an array with 'new Cvec3[n]' all
    elements are stored serial.
    But back to the reorder problem. You say that reorder is not a problem if I
    use a struct instead of a class with public/private members, right?

    Regards, Axel
     
    Axel F, Jan 12, 2006
    #4
  5. Hi!

    "Axel F" <>:

    > class Cvec3
    > {
    > public:
    > float* begin() { return &x; }
    > operator float*() { return &x; }
    > public:
    > float x,y,z;
    > };
    >
    > and I want to use c-function which take a pointer to float like some gl
    > functions. So I have defined the function begin(). I know this works and I
    > had never problems with this.
    > Somebody of my team says now, that it is not secure to do this, cause the
    > compiler can reorder the members x,y,z or can change pack alignment. He says
    > that nothing can be found about this in the c++ standard.


    Hmm, I can't call me an expert, but do you want do rely on (c being an Cvec3 object) c.begin()+1 pointing to y? That looks risky to me.

    Regards,
    Matthias
     
    Matthias Kluwe, Jan 27, 2006
    #5
  6. Axel F

    Guest

    Axel F wrote:
    > Hi,
    >
    > I have question about the following.
    > For instance I have a class like
    >
    > class Cvec3
    > {
    > public:
    > float* begin() { return &x; }
    > operator float*() { return &x; }
    > public:
    > float x,y,z;
    > };
    >
    > and I want to use c-function which take a pointer to float like some gl
    > functions. So I have defined the function begin(). I know this works and I
    > had never problems with this.
    > Somebody of my team says now, that it is not secure to do this, cause the
    > compiler can reorder the members x,y,z or can change pack alignment. He says
    > that nothing can be found about this in the c++ standard.


    He/she is right in that you cannot depend on y immediately following x
    or anything about their relative locations. begin()++ could be or do
    anything.

    If something is not specifically specified by the standard it is
    undefined (see definition of undefined behavior 1.3.12)...meaning there
    is absolutely no restriction on behavior. I don't know if the fact
    that you can't depend on packing and ordering is specified or not.
     
    , Jan 27, 2006
    #6
  7. Axel F

    Guest

    Axel F wrote:

    > Thank you for your answer.
    > the padding seems to be no problem, cause x,y,z are of the same type
    > (4-byte), so that all elements are placed serial in memory also if I use
    > 8-byte alignment.


    It is definately a problem. It is undefined behavior. It may work for
    you now but could break in ways VERY difficult to figure out at any
    time. Once again, you cannot depend on the behavior of your construct;
    the _only_ thing you can depend on is the return value of begin() will
    be the address of the member 'x'.

    It's like having a car that could explode for no reason whatsoever at
    any moment...would you drive it even though it is currently working and
    seems to be safe??!! Using your class could cost many hours of work
    down the road and it would be very ill-advised to use in any project,
    much less anything of production value.
     
    , Jan 27, 2006
    #7
  8. > It is definately a problem. It is undefined behavior. It may work for
    > you now but could break in ways VERY difficult to figure out at any
    > time. Once again, you cannot depend on the behavior of your construct;
    > the _only_ thing you can depend on is the return value of begin() will
    > be the address of the member 'x'.


    What if you make it a union like this?

    union
    {
    float data[3];
    struct
    {
    float x;
    float y;
    float z;
    }
    };

    Doesnt that enforce the alignment of x,y,z because data is aligned to 4 byte
    boundaries?

    If it doesnt, you could still use a #pragma pack(4) to enforce it
     
    Frank Neuhaus, Jan 27, 2006
    #8
  9. Axel F

    Guest

    Frank Neuhaus wrote:
    > > It is definately a problem. It is undefined behavior. It may work for
    > > you now but could break in ways VERY difficult to figure out at any
    > > time. Once again, you cannot depend on the behavior of your construct;
    > > the _only_ thing you can depend on is the return value of begin() will
    > > be the address of the member 'x'.

    >
    > What if you make it a union like this?
    >
    > union
    > {
    > float data[3];
    > struct
    > {
    > float x;
    > float y;
    > float z;
    > } vars;
    > };


    edit: gave struct a name...
    >
    > Doesnt that enforce the alignment of x,y,z because data is aligned to 4 byte
    > boundaries?


    AFAIK there is nothing saying vars is aligned to 4 byte boundaries.

    data and vars need not be the same size. They do have the same
    address, but beyond that there isn't much that is guaranteed. I don't
    know if vars.x and data[0] have the same address for sure; I have often
    seen code that assums so but someone more familiar with the std will
    need to say if it is guaranteed behavior. I do know, from previous
    discussions, that data[1] and vars.y don't have to align.
     
    , Jan 27, 2006
    #9
  10. Axel F

    persenaama Guest

    That works but not very likely reflect the intended use for the class
    (talking about the reference members). Ofcourse, if it isn't a problem
    that sizeof(Cvec3) >= sizeof(float)*3 (more likely to be double or
    triple the size on common target platforms.
     
    persenaama, Jan 27, 2006
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Max
    Replies:
    1
    Views:
    484
    Joe Kesselman
    Sep 22, 2006
  2. P4trykx
    Replies:
    2
    Views:
    1,826
    bruce barker
    Jan 31, 2007
  3. Knut Krueger
    Replies:
    2
    Views:
    447
    Knut Krueger
    May 21, 2007
  4. james_027

    class attributes & data attributes

    james_027, Jun 20, 2007, in forum: Python
    Replies:
    2
    Views:
    377
    Bruno Desthuilliers
    Jun 20, 2007
  5. Kyle Schmitt
    Replies:
    3
    Views:
    194
    Kyle Schmitt
    Jul 24, 2007
Loading...

Share This Page