Pointers and Arrays

Pages: 12
closed account (o1vk4iN6)
Kind of looking for people that know their way around the C++ standard for this and might be able to provide a reference to. Say I have a class like this and I use a pointer as an array, whether this can produce undefined behavior or not...

1
2
3
4
5
struct Point
{
    float x, y;
    float& operator [] (int i) { return (&x)[i]; }
};


I know I've seen some libraries do this (Doom3's idLib's Vectors do this) and some opengl implementations when passing pointers to attributes of a vertex ie:

1
2
3
4
5
6
7
8
struct Vertex
{
    float x, y, z;
    float u, v;
} vertex;

glVertexAttribPointer( ..., &vertex.x );
Your first example doesn't make sense to me. Point::x is not an array of floats, so why would you index into it? I've seen people index into variables to get individual bytes (a bad idea because it doesn't take endianness into account) but I don't know what you're trying to do.

The second example is just passing a pointer to float to a function which seems fine to me.
I think the OP is talking about indexing an {float x, y, z, u, v;} struct as if it was an array of floats, staring with a pointer to x.

If that is the case, it is undefined behavior from the standard point of view because pointer arithmetic is only defined within an array (and a compiler is free to ignore that code, or warn about accessing an array out of bounds, etc)
1
2
3
4
5
6
7
8
9
struct CubbiVertex
{
    float p[5]
    ,    &x {p[0]}
    ,    &y {p[1]}
    ,    &z {p[2]}
    ,    &u {p[3]}
    ,    &v {p[4]};
};
http://ideone.com/sZVjNN
Last edited on
closed account (o1vk4iN6)

@cubbi
So it is undefined but for the most part I've never seen it fail. Most math libraries I see define vectors as 3 floating point components and are still used and passed to the GPU. Almost feel as though the standard should define something of the sort.

@LB
Again idk why you would want to double the size of a structure and number of memory accesses, not to mention initialization of those references. Especially considering this is a vertex and the shear number that are going to exist, this is something you don't really want.

Last edited on
You can define x and y as references. For example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
 
template <typename T>
class Point
{
public:
   Point( const T &x, const T &y ) : a( { x, y } ) {}
   Point() : Point( T(), T() ) {} 
 
   T &x = a[0];
   T &y = a[1];
 
   const T & operator []( size_t i ) const { return ( a[i] ); }
   T & operator []( size_t i ) { return ( a[i] ); }
 
private:
   T a[2];
 };
 
int main()
{
   Point<int> p( 10, 20 );
 
   std::cout << "p.x  = " << p.x << ", p.y  = " << p.y << std::endl;
   std::cout << "p[0] = " << p[0] << ", p[1] = " << p[1] << std::endl;
}
@vlad
Why have an operator[] that returns const references and one that doesn't?
One is a const method and the other isn't
¿wouldn't an union be useful in this case?
Edit: it seems that it isn't.

Simply use member functions
1
2
3
4
5
6
7
8
9
10
class point{
public:
   T coord[3];
   T& x(){
      return coord[0];
   }
   T& operator[](int index){
      return coord[index];
   }
};
Last edited on
It's undefined behaviour to write to one union member and then read from another expecting them to share the same memory, so no. You can only read from the one last written.
@chrisname

@vlad
Why have an operator[] that returns const references and one that doesn't?


The const operator will allow to deal with const objects of the type Point or with const references to objects of the type Point.

For example


1
2
3
4
5
template <typename T>
std::ostream & operator <<( std::ostream &os, const Point<T> &p )
{
   return ( os << "<" << p[0] << ", " << p[1] << ">" );
}


Or

1
2
3
4
const Point<double> p1( 10.0, 20.0 );
const Point<double> p2( 5.0, 15.0 );

int distance = std::sqrt( std::pow( ( p1[0] - p2[0] ), 2 ) + std::pow( ( p1[1] - p2[1] ), 2 ) );
Last edited on
closed account (o1vk4iN6)
Yah unions are undefined as well for this example, if you compiler supports anonymous structures this is also commonly used:

1
2
3
4
5
6
7
8
9
10
11
struct Point
{
    union
    {
        struct
        {
            float x, y;
        };
        float v[2];
    };
};


@vlad
Again using references for a vector is not ideal, you can be double if not tripling the size of the vector depending on the architecture you are on.


I guess the point being, even though this is all undefined almost every math library I see used with opengl defines a vector with variables instead of an array.
Last edited on
Are these math libraries C or C++?
Why do you need to be able to index into the vertex like an array anyway? And why can't you, knowing that there are only two values in the array, just do
1
2
3
4
5
6
7
8
9
10
11
struct Point {
    float x, y;
    float& operator[](int index)
    {
        switch (index) {
            case  0: return x;
            case  1: return y;
            default: throw std::runtime_error("Point::operator[] only defined for indices 0 and 1");
        }
    }
};

It's no worse than any other solution that hardcodes the size of the array, and it doesn't take any extra memory because every Point object share instance methods by using a hidden parameter (this).
Last edited on
closed account (o1vk4iN6)
OpenGL's API takes a pointer to an array so it would have to be an array to be defined. You'd have 2 comparisons in that solution though, just for accessing an index (I don't think any compiler creates a jump table for 2 cases, even than you would need a comparison or 2 for the default case) which compared to an indexed array would be slower. Though not really concerned about the operator[] so much as defined behavior to be compatible with opengl.

@ cire

Both just thinking off the top of my head, I think Microsoft Directx's (can't remember how directx passes stuff to the gpu) math library is written in C (yah it's pretty nasty) and then others like GLM written in C++.
Last edited on
If you need to have an array, then what about
1
2
3
4
5
6
7
8
9
10
11
struct Point {
    float x, y;

    std::shared_ptr<float> to_array()
    {
        float* array = new float[2]();
        array[0] = x;
        array[1] = y;
        return std::shared_ptr<float>(array);
    }
};

This way, the extra memory only exists temporarily and there's little risk of memory leakage, although I suppose there's a fair amount of overhead with the object construction and DMA. You would use it like this:
glFoo(my_point.to_array().get());
How's that?
Last edited on
closed account (o1vk4iN6)
std::shared_ptr<float[]>
Arrays require []. Hmm at least you do for unique ptr. Doesn't look like shared_ptr support dynamically allocated arrays.

Creating a temporary value might work in some cases, but still allocating memory for something like that is slow and not ideal.
Last edited on
> Why do you need to be able to index into the vertex like an array anyway?
¿why do you need `x', `y' access?
An array is easier to extend, the algorithms just need to adjust the upper limit.


> almost every math library I see used with opengl defines a vector with variables instead of an array.
¿by instance?

> Doesn't look like shared_ptr support dynamically allocated arrays.
http://www.cplusplus.com/reference/memory/shared_ptr/shared_ptr/ (look for deleter)
closed account (o1vk4iN6)
¿by instance?
Both just thinking off the top of my head, I think Microsoft Directx's (can't remember how directx passes stuff to the gpu) math library is written in C (yah it's pretty nasty) and then others like GLM written in C++.


Doesn't support it in the way std::unique_ptr<float[]> does.
xerzi wrote:
std::unique_ptr<float[]>
Why would you want a unique pointer to a pointer?
Pages: 12