is this portable, conforming to standard, elegant?

J

Jerry Coffin

class vector3
{
public:
union
{
float[3] data;

No -- in fact, this isn't even well-formed. Presumably you meant:

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

access with data array is convenient for file io and x,y,z for other things

No -- no padding is allowed between the elements of the array, but it is
allowed between x, y and z. You could make a pretty good case that x and
data[0] can be accessed interchangeably and legitimately, but beyond
that it's likely to break. You could do something on this general order:

struct vector3 {
float data[3];
int &x, &y, &z;

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

or:

struct vector3 {
int x, y, z;

int &operator[](size_t index) {
if (index == 0)
return x;
else if (index == 1)
return y;
else // bounds-check if you see fit.
return z;
}
};

The difference between the two is a potential time/space tradeoff: the
first version may easily make a vector3 twice as big. The second might
make access via operator[] slower.
 
J

Jerry Coffin

I'm not sure that it is very portable. I have seen that, depending on
compiler options, members inside a struct can change their relative
position.
I don't think there is anything in the standard that says for the
following x,y and z must have consecutive memory addresses.
union
{
float[3] data;
struct
{
float x, y, z;
};
};

&x == data ??
&y == data + 1??
&z == data + 2 ??

I think the compiler has the freedom to choose any memory addresses,
so we probably can have &x == data + N, 0 < N <= 2

Not exactly. The anonymous struct containing x, y and z is an aggregate,
(section 8.5.1) so the elements must be allocated in ascending order.
They could/can be rearranged only if separated by an access specifier.
Padding is allowed betwen them, but not before the first element.

'data' is an array, so the elements must be allocated consecutively (no
padding is allowed before or between elements).

Each element in the union must reside at the same address, so data[0]
and x must have the same address. Due the possibility of padding
before/after y and z, however, their addresses may not be the same as
data[1] and data[2] respectively.

There are a few other details that aren't really right, (e.g. the syntax
of the array definition, lack of a tag on the union so it can't really
be used) but I doubt these are really relevant to the OP's question.
 
A

Alexei Polkhanov

class U
{
// Normally, x,y,z would be private, but OP needs them
// to be public
public:
float x;
float y;
float z;

// operator[] should be public
public:
// Should also provide a const version of this
float& operator[](int index)
{
if (index == 0)
return x;
else if (index == 1)
y;
else if (index == 2)
return z;
else
// Throw exception or something else appropriate
};

};

Personally, to me this then becomes the "best compromise" solution to
the original poster's problem. It allows clients to continue using
x,y,z member variables but also access using array index notation. It

Agree, this solution is much better, however I was under impression
that
using "union" had to be part of the solution since it was part of the
question.

- Alexei.
 
E

Emmanuel Deloget

class U
{
// Normally, x,y,z would be private, but OP needs them
// to be public
public:
float x;
float y;
float z;
// operator[] should be public
public:
// Should also provide a const version of this
float& operator[](int index)
{
if (index == 0)
return x;
else if (index == 1)
y;
else if (index == 2)
return z;
else
// Throw exception or something else appropriate
};

Personally, to me this then becomes the "best compromise" solution to
the original poster's problem. It allows clients to continue using
x,y,z member variables but also access using array index notation. It

Agree, this solution is much better, however I was under impression
that
using "union" had to be part of the solution since it was part of the
question.

- Alexei.

I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block. The static array of
pointer to members allows a direct access to the variable you need, is
extensible, and doesn not add any space to the class itself, since
it's a class static. As I said, I'm not really sure about the init
time of this array, but given the fact that it's a static POD array,
it should be initialized quite early. Further refinement (throwing a
out_of_range exception) is not difficult to implement (as it only
requires a test against the size of the array, and the mandatory throw
statement). The simplicity of operator[] will make this method a good
candidate for inlining, so in the end the code is quite efficient.

Now, there may be some problems I haven't seen (I don't see every
problem) - if you find some, please tell me.

Regards,

-- Emmanuel Deloget
 
C

Craig Scott

class U
{
// Normally, x,y,z would be private, but OP needs them
// to be public
public:
float x;
float y;
float z;
// operator[] should be public
public:
// Should also provide a const version of this
float& operator[](int index)
{
if (index == 0)
return x;
else if (index == 1)
y;
else if (index == 2)
return z;
else
// Throw exception or something else appropriate
};
};
Personally, to me this then becomes the "best compromise" solution to
the original poster's problem. It allows clients to continue using
x,y,z member variables but also access using array index notation. It
Agree, this solution is much better, however I was under impression
that
using "union" had to be part of the solution since it was part of the
question.
- Alexei.

I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block. The static array of
pointer to members allows a direct access to the variable you need, is
extensible, and doesn not add any space to the class itself, since
it's a class static. As I said, I'm not really sure about the init
time of this array, but given the fact that it's a static POD array,
it should be initialized quite early. Further refinement (throwing a
out_of_range exception) is not difficult to implement (as it only
requires a test against the size of the array, and the mandatory throw
statement). The simplicity of operator[] will make this method a good
candidate for inlining, so in the end the code is quite efficient.

Now, there may be some problems I haven't seen (I don't see every
problem) - if you find some, please tell me.

Probably the biggest weakness is that using the static array makes
your class unsuitable for use in a multi-threaded application. If your
app is single threaded, then it's fine.
 
C

Craig Scott

I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block.

No need to be reluctant to defend your ideas. A robust discussion is
what makes this list and other like it interesting, not to mention
educational. :)
 
K

Kai-Uwe Bux

Craig said:
On Feb 9, 5:05 pm, "Craig Scott" <[email protected]> wrote:
class U
{
// Normally, x,y,z would be private, but OP needs them
// to be public
public:
float x;
float y;
float z;
// operator[] should be public
public:
// Should also provide a const version of this
float& operator[](int index)
{
if (index == 0)
return x;
else if (index == 1)
y;
else if (index == 2)
return z;
else
// Throw exception or something else appropriate
};

Personally, to me this then becomes the "best compromise" solution to
the original poster's problem. It allows clients to continue using
x,y,z member variables but also access using array index notation. It
Agree, this solution is much better, however I was under impression
that
using "union" had to be part of the solution since it was part of the
question.
- Alexei.

I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block. The static array of
pointer to members allows a direct access to the variable you need, is
extensible, and doesn not add any space to the class itself, since
it's a class static. As I said, I'm not really sure about the init
time of this array, but given the fact that it's a static POD array,
it should be initialized quite early. Further refinement (throwing a
out_of_range exception) is not difficult to implement (as it only
requires a test against the size of the array, and the mandatory throw
statement). The simplicity of operator[] will make this method a good
candidate for inlining, so in the end the code is quite efficient.

Now, there may be some problems I haven't seen (I don't see every
problem) - if you find some, please tell me.

Probably the biggest weakness is that using the static array makes
your class unsuitable for use in a multi-threaded application. If your
app is single threaded, then it's fine.

I am not sure about that.

The proposed solution was essentially this:

struct Vector3 {

float x, y, z;

float const & operator[](unsigned int i) const {
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}

float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}

};

#include <iostream>

int main ( void ) {
Vector3 a;
a[1] = 2;
std::cout << a.y << '\n';
}


The static array is const. It never changes, so apart from initialization
issues, I do not see a problem in multithreading (probably, I am very naive
here:). If there is a problem, one could make operator[] atomic using some
RAII mutex wrapper so that reads to the static data is properly serialized.
That would take care of the initialization issue, as well. Code could look
like this:

class Vector3 {

static some_lock_type the_lock;

public:

float x, y, z;

float const & operator[](unsigned int i) const {
SomeLockAcquiringWrapper the_guard ( the_lock );
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}

float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}

};

However, it might be to costly to do that :-(


Best

Kai-Uwe Bux
 
C

Craig Scott

Craig said:
class U
{
// Normally, x,y,z would be private, but OP needs them
// to be public
public:
float x;
float y;
float z;
// operator[] should be public
public:
// Should also provide a const version of this
float& operator[](int index)
{
if (index == 0)
return x;
else if (index == 1)
y;
else if (index == 2)
return z;
else
// Throw exception or something else appropriate
};
};
Personally, to me this then becomes the "best compromise" solution to
the original poster's problem. It allows clients to continue using
x,y,z member variables but also access using array index notation. It
Agree, this solution is much better, however I was under impression
that
using "union" had to be part of the solution since it was part of the
question.
- Alexei.
I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block. The static array of
pointer to members allows a direct access to the variable you need, is
extensible, and doesn not add any space to the class itself, since
it's a class static. As I said, I'm not really sure about the init
time of this array, but given the fact that it's a static POD array,
it should be initialized quite early. Further refinement (throwing a
out_of_range exception) is not difficult to implement (as it only
requires a test against the size of the array, and the mandatory throw
statement). The simplicity of operator[] will make this method a good
candidate for inlining, so in the end the code is quite efficient.
Now, there may be some problems I haven't seen (I don't see every
problem) - if you find some, please tell me.
Probably the biggest weakness is that using the static array makes
your class unsuitable for use in a multi-threaded application. If your
app is single threaded, then it's fine.

I am not sure about that.

The proposed solution was essentially this:

struct Vector3 {

float x, y, z;

float const & operator[](unsigned int i) const {
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}

float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}

};

#include <iostream>

int main ( void ) {
Vector3 a;
a[1] = 2;
std::cout << a.y << '\n';

}

The static array is const. It never changes, so apart from initialization
issues, I do not see a problem in multithreading (probably, I am very naive
here:). If there is a problem, one could make operator[] atomic using some
RAII mutex wrapper so that reads to the static data is properly serialized.
That would take care of the initialization issue, as well. Code could look
like this:

class Vector3 {

static some_lock_type the_lock;

public:

float x, y, z;

float const & operator[](unsigned int i) const {
SomeLockAcquiringWrapper the_guard ( the_lock );
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}

float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}

};

However, it might be to costly to do that :-(



Your static array is const but you cast away the const-ness with your
non-const operator[], so clients would be free to try to change the
contents with potentially lethal results. The use of locking will, of
course, get you around the data corruption issue, but I doubt clients
of the class would be expecting to pay the penalty of locking just to
access a class like this. I certainly wouldn't.
 
K

Kai-Uwe Bux

Craig said:
Craig said:
On 13 fév, 20:00, "Alexei Polkhanov" <[email protected]> wrote:
On Feb 9, 5:05 pm, "Craig Scott" <[email protected]> wrote:
class U
{
// Normally, x,y,z would be private, but OP needs them
// to be public
public:
float x;
float y;
float z;
// operator[] should be public
public:
// Should also provide a const version of this
float& operator[](int index)
{
if (index == 0)
return x;
else if (index == 1)
y;
else if (index == 2)
return z;
else
// Throw exception or something else appropriate
};

Personally, to me this then becomes the "best compromise" solution
to the original poster's problem. It allows clients to continue
using x,y,z member variables but also access using array index
notation. It
Agree, this solution is much better, however I was under impression
that
using "union" had to be part of the solution since it was part of
the question.
- Alexei.
I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block. The static array of
pointer to members allows a direct access to the variable you need, is
extensible, and doesn not add any space to the class itself, since
it's a class static. As I said, I'm not really sure about the init
time of this array, but given the fact that it's a static POD array,
it should be initialized quite early. Further refinement (throwing a
out_of_range exception) is not difficult to implement (as it only
requires a test against the size of the array, and the mandatory throw
statement). The simplicity of operator[] will make this method a good
candidate for inlining, so in the end the code is quite efficient.
Now, there may be some problems I haven't seen (I don't see every
problem) - if you find some, please tell me.
Probably the biggest weakness is that using the static array makes
your class unsuitable for use in a multi-threaded application. If your
app is single threaded, then it's fine.

I am not sure about that.

The proposed solution was essentially this:

struct Vector3 {

float x, y, z;

float const & operator[](unsigned int i) const {
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}

float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}

};

#include <iostream>

int main ( void ) {
Vector3 a;
a[1] = 2;
std::cout << a.y << '\n';

}

The static array is const. It never changes, so apart from initialization
issues, I do not see a problem in multithreading (probably, I am very
naive here:). If there is a problem, one could make operator[] atomic
using some RAII mutex wrapper so that reads to the static data is
properly serialized. That would take care of the initialization issue, as
well. Code could look like this:

class Vector3 {

static some_lock_type the_lock;

public:

float x, y, z;

float const & operator[](unsigned int i) const {
SomeLockAcquiringWrapper the_guard ( the_lock );
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}

float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}

};

However, it might be to costly to do that :-(



Your static array is const but you cast away the const-ness with your
non-const operator[], so clients would be free to try to change the
contents with potentially lethal results.


No, they can't even try: the const_cast is not applied to the static
object "proxy" at any time, it is applied to the object for which the
member function operator[] is called. That does not propagate to static
members. Nobody, at any time, can change the pointer-to-member entries in
proxy.

However, if you feel uncomfortable using the harmless const_cast<> trick,
you can easily rewrite the whole thing equivalently as follows:

#include <cassert>
#include <cstddef>

class Vector3 {

static
float Vector3::* const
proxy ( std::size_t i ) {
static float Vector3::* const the_proxy [3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return ( the_proxy );
}

public:

float x, y, z;

float const & operator[] ( std::size_t i ) const {
assert( i < 3 );
return (*this).*(proxy(i));
}

float & operator[] ( std::size_t i ) {
assert( i < 3 );
return (*this).*(proxy(i));
}

};


#include <iostream>

int main ( void ) {
Vector3 a;
a[1] = 2;
std::cout << a.y << '\n';
}
The use of locking will, of
course, get you around the data corruption issue, but I doubt clients
of the class would be expecting to pay the penalty of locking just to
access a class like this. I certainly wouldn't.

I still don't see any data corruption issue. Could you present a scenario,
in code, where it might happen.


Best

Kai-Uwe Bux
 
P

peter koch

[snip]

I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block.

I have to agree with you: that idea is very nice. If I had to choose
anything but the dirty hack, your solutioon is by far the most elegant
and the cleanest way out. The only problem I have with your solution
(and this is valid for all the non-hacks) is the overhead which I
guess would be present also for the best optimising compilers.
[snip]
Now, there may be some problems I haven't seen (I don't see every
problem) - if you find some, please tell me.
Only the potential multithreading problem which should be easily
solvable.

/Peter
 
E

Emmanuel Deloget

Probably the biggest weakness is that using the static array makes
your class unsuitable for use in a multi-threaded application. If your
app is single threaded, then it's fine.

No, this is not a problem here. The static array is never modified -
it is private to vector3d and is not modified by any member of this
class. It means that you don't have to worry about using it in a
multithreaded application - you can view it as yet another global
class static constant.

To you defense, I should have made the code const correct. Here is the
corrected code snippet:

class vector3d
{
static float vector3d::* const proxy[3];
public:
float x, y, z;
float& operator[](unsigned int i) { return (*this).*proxy; }
};

float vector3d::* const vector3d::proxy[3] =
{ &vector3d::x, &vector3d::y, &vector3d::z };

int main()
{
vector3d v;
v[0] = 1.0f;
}

Now, the "proxy" static array is immutable - so it won't give you
headaches if you use it in a multi-threaded environment.

Regards,

-- Emmanuel Deloget
 
C

Craig Scott

Probably the biggest weakness is that using the static array makes
your class unsuitable for use in a multi-threaded application. If your
app is single threaded, then it's fine.

No, this is not a problem here. The static array is never modified -
it is private to vector3d and is not modified by any member of this
class. It means that you don't have to worry about using it in a
multithreaded application - you can view it as yet another global
class static constant.

To you defense, I should have made the code const correct. Here is the
corrected code snippet:

class vector3d
{
static float vector3d::* const proxy[3];
public:
float x, y, z;
float& operator[](unsigned int i) { return (*this).*proxy; }

};

float vector3d::* const vector3d::proxy[3] =
{ &vector3d::x, &vector3d::y, &vector3d::z };

int main()
{
vector3d v;
v[0] = 1.0f;

}

Now, the "proxy" static array is immutable - so it won't give you
headaches if you use it in a multi-threaded environment.

Regards,

-- Emmanuel Deloget


Apologies required! Sorry, I am guilty of not reading your code
closely enough. Yes, your solution is as safe in a multi-threaded
application as any other code (ie the static proxy is not a problem
from a multi-threaded point of view, contrary to my earlier post).

One potential weakness still concerns me though. The actual
initialization of the static array would probably need to be done
outside of the header, otherwise there will be a problem with multiple
instances of the array. That means the compiler would not know that
the operator[] call would always return x, y or z. Hence, a function
call would always be required whenever the operator[] was used,
whereas it would seem reasonable for a modest proportion of people to
expect that operator[] should not be forced to pay this penalty for a
class such as this. Rather, they would probably expect that compilers
should be able to optimize it all away to a direct access to the
underlying data (ie inline everything to do with the call). Apart from
this though, the idea does seem to be quite elegant.
 
C

Craig Scott

Craig said:
Craig Scott wrote:
class U
{
// Normally, x,y,z would be private, but OP needs them
// to be public
public:
float x;
float y;
float z;
// operator[] should be public
public:
// Should also provide a const version of this
float& operator[](int index)
{
if (index == 0)
return x;
else if (index == 1)
y;
else if (index == 2)
return z;
else
// Throw exception or something else appropriate
};
};
Personally, to me this then becomes the "best compromise" solution
to the original poster's problem. It allows clients to continue
using x,y,z member variables but also access using array index
notation. It
Agree, this solution is much better, however I was under impression
that
using "union" had to be part of the solution since it was part of
the question.
- Alexei.
I (really) dislike being the one who says "there is a better solution,
look at mine", but that's going to be what I'm going to do - as the
solution I proposed is quite elegant, standard-proof, and doesn't
require any (endless?) if/then/if/then/else block. The static array of
pointer to members allows a direct access to the variable you need, is
extensible, and doesn not add any space to the class itself, since
it's a class static. As I said, I'm not really sure about the init
time of this array, but given the fact that it's a static POD array,
it should be initialized quite early. Further refinement (throwing a
out_of_range exception) is not difficult to implement (as it only
requires a test against the size of the array, and the mandatory throw
statement). The simplicity of operator[] will make this method a good
candidate for inlining, so in the end the code is quite efficient.
Now, there may be some problems I haven't seen (I don't see every
problem) - if you find some, please tell me.
Probably the biggest weakness is that using the static array makes
your class unsuitable for use in a multi-threaded application. If your
app is single threaded, then it's fine.
I am not sure about that.
The proposed solution was essentially this:
struct Vector3 {
float x, y, z;
float const & operator[](unsigned int i) const {
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}
float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}
};
#include <iostream>
int main ( void ) {
Vector3 a;
a[1] = 2;
std::cout << a.y << '\n';
}
The static array is const. It never changes, so apart from initialization
issues, I do not see a problem in multithreading (probably, I am very
naive here:). If there is a problem, one could make operator[] atomic
using some RAII mutex wrapper so that reads to the static data is
properly serialized. That would take care of the initialization issue, as
well. Code could look like this:
class Vector3 {
static some_lock_type the_lock;
public:
float x, y, z;
float const & operator[](unsigned int i) const {
SomeLockAcquiringWrapper the_guard ( the_lock );
static float Vector3::* const proxy[3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return (*this).*proxy;
}
float & operator[] ( unsigned int i ) {
return
( const_cast<float&>
( const_cast<Vector3 const *>(this)->operator[](i) ) );
}
};
However, it might be to costly to do that :-(

Your static array is const but you cast away the const-ness with your
non-const operator[], so clients would be free to try to change the
contents with potentially lethal results.

No, they can't even try: the const_cast is not applied to the static
object "proxy" at any time, it is applied to the object for which the
member function operator[] is called. That does not propagate to static
members. Nobody, at any time, can change the pointer-to-member entries in
proxy.

However, if you feel uncomfortable using the harmless const_cast<> trick,
you can easily rewrite the whole thing equivalently as follows:

#include <cassert>
#include <cstddef>

class Vector3 {

static
float Vector3::* const
proxy ( std::size_t i ) {
static float Vector3::* const the_proxy [3] =
{ &Vector3::x, &Vector3::y, &Vector3::z };
return ( the_proxy );
}

public:

float x, y, z;

float const & operator[] ( std::size_t i ) const {
assert( i < 3 );
return (*this).*(proxy(i));
}

float & operator[] ( std::size_t i ) {
assert( i < 3 );
return (*this).*(proxy(i));
}

};

#include <iostream>

int main ( void ) {
Vector3 a;
a[1] = 2;
std::cout << a.y << '\n';

}
The use of locking will, of
course, get you around the data corruption issue, but I doubt clients
of the class would be expecting to pay the penalty of locking just to
access a class like this. I certainly wouldn't.

I still don't see any data corruption issue. Could you present a scenario,
in code, where it might happen.

Best

Kai-Uwe Bux


Ah, thanks for your patience. I had not properly read the previous
postings and was incorrect in my statements. See my other recent post
in this topic for remaining niggles with this otherwise elegant
solution. :)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,139
Latest member
JamaalCald
Top