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?
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.
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.
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.
Show 5 more comments