Why does read-access of int*const& cause segmentation fault?

Why does the below read-access of an int*const& result in a segmentation fault?

#include <iostream>

class X{
    int A[3][4] = {0};
public:
    int*const&p=*A;
    void print()const{
        for(int i=0;i<3;++i){
            for(int j=0;j<4;++j){
                std::cout << A[i][j] << " , ";
            }
            std::cout << "\n";
        }
    }
};

int main() {
    X x;
    x.p[2] = 3;
    x.print(); // until this point, everything works as intended

    std::cout << x.p[2] << "\n"; // why does read-access of p trigger segmentation fault?
}

Output

0 , 0 , 3 , 0 , 
0 , 0 , 0 , 0 , 
0 , 0 , 0 , 0 , 
Segmentation fault

Application Context

I want an n-D array A for internal computations with easier indexing in a dynamic programming context, but the external interface requests a pointer p to a 1D array.

Potential Explanation

The above code works when replacing int*const& p=*A; with int*const p=*A;. Is the real issue in the fact that the internal int array of A[][] is inaccessible for assignment?

  • 3

    Turn on your compiler warnings. My compiler tells me twice that what happens here is wrong: godbolt.org/z/noffGbdc4. Undefined Behaviour can do anything, including “crashing in a seemingly unrelated place”.

    – 

  • Why would you even want to use ` int*const&p` ? Ever thought about returning a const reference to a std::array<std::array<int,4>,3> (through a getter function, instead of a public member).

    – 




  • @Yksisarvinen So you say line 6 is the incorrect command for acquiring a pointer member that points at A[0][0] ? Is there then a way to construct such a member at all?

    – 

  • Don’t write code like that. It’s blatant obfuscation and just doesn’t add or do anything useful. Be precise, be explicit, and write good, clean and maintainable code.

    – 




  • 3

    You expose a reference to a pointer, but you have no pointer that lives long enough. The only pointer you have is a temporary which dies immediately after initialising the reference. The reference thus becomes dangling.

    – 

In current C++ you would use std::array and references to that array (just like any other C++ object, you can return std::array from a function).
You should not have public data, always provide getters (easier to refactor certainly with the auto keyword).

#include <array>
#include <iostream>

class X
{
public:

    //read only (used when there is a "const X" or "const X&" being used
    //like in stream operator below
    // No need type std::array<std::array<int, 4>, 3> over and over again, just use auto
    const auto& get_values() const noexcept
    {
        return m_values;
    }

    // read/write for non-const situations.
    auto& get_values() noexcept
    {
        return m_values;
    }

private:
    // nice thing about std::array is you can return
    // it from functions by (const) reference (like get_values)
    std::array<std::array<int, 4>, 3> m_values{};
};


// replacement of your print, generic output to a stream
std::ostream& operator<<(std::ostream& os, const X& x)
{
    auto& values = x.get_values();

    // whenever you can use range based for loops
    for (const auto& row : values)
    {
        bool comma{ false };
        for (const auto& value : row)
        {
            if (comma) os << ", ";
            os << value;
            comma = true;
        }
        os << "\n";
    }

    return os;
}
    

int main() 
{
    X x;

    // get a reference to the 2D array
    auto& values = x.get_values();

    // then assign a value into this array
    // this is also where one of your mistakes was, assinging an int to a whole row
    values[2][2] = 3;
 
    std::cout << x; // use stream operator for X

    return 0;
}

You could always try to overload the subscriptor operator to get the specific element of A that you like as such:

int &X::operator[](int index)
{
    return A[index];
}

But this method above cannot handle 2-dimensional arrays. However there is a thread that references this very topic: operator overloading [][] 2d array c++

Hope that answers your question.

Leave a Comment