c++arraysstackindexoutofboundsexception

c++ stack order asserted?


Is the following code under every compliant compiler optimization asserted to return the value 14? Is this recommendable to use? Is this more efficient than introducing two pointers onto a common array? Has the below stack technique a specific name? Which better practice yields the exact same binary upon compilation under reasonable or admirable assumptions?

#include <iostream>

class A{
public:
    double x[10];
    double y[10];
};

int main(){
    A a;
    a.y[3] = 14;
    std::cout << a.x[13] << "\n";
}

Where can I look up determinations like these? (links, references). I guess there is a trick to reading the standard efficiently.


Solution

  • A number of people have already pointed out in the comments that your code currently has undefined behavior.

    As far as ordering goes, you are guaranteed that as you've defined things right now x and y are in order--that is, y will have a higher memory address than x. But there could be padding in between them, so that there's less overlap than you expect, or possibly no overlap at all. In addition, the standard is written to allow (but not require) that array indices can be checked for validity, so even if they're immediately next to each other, the compiler is allowed to check that since you defined x to have 10 elements, any attempt at indexing beyond the 10th element will fail (e.g., cause a hardware interrupt or fault).

    That leaves the question about how to get the result you apparently want, but with defined behavior. You have a couple of choices. One is to allocate a single array, and add an alias that allows you to treat half of it as if it were a separate array:

    #include<iostream>
    
    class A{
    public:
        double x[20];
        double *y = &x[10];
    };
    
    int main(){
        A a;
        a.y[3] = 14;
        std::cout << a.x[13] << "\n";
    }
    

    The other direction you could go would be to keep the two arrays separate, but then add a small proxy to allow addressing into both arrays as if they were one:

    #include<iostream>
    
    class proxy {
        double *x_;
        size_t N;
        double *y_;
    public:
        template <class T, std::size_t N>
        proxy(T (&x_)[N], T *y) : x_(x_), N(N), y_(y) {}
    
        double &operator[](std::size_t n) {
            if (n < N)
                return x_[n];
            else
                return y_[n-N];
        }
    };
    
    class A{
        double x_[10];
    public:
        double y[10];
        proxy x{x_, y};
    };
    
    int main(){
        A a;
        a.y[3] = 14;
        std::cout << a.x[13] << "\n";
    }
    

    Unless you really need to use separate arrays for the two items, the first is probably preferable – it's clearly simpler and probably faster.