Adding empty destructor generates seg fault.

The following code compiles but generates a segfault at runtime. If I remove the empty destructor or the last statement in main, the code runs without problem. Why? this is strange!

My intent to add "delete [] data;" to the destructor, but that doesn't work either.

More broadly, how should I create and destroy the array (note, I know I could use vector<> in this case but I still would like to understand what is going wrong here and how it should be done properly.

---------------------------------------------
#include <iostream>

class map{
public:
double * data[];

map(int size){
*data = new double[size];
}

~map(){}

void setitem(int i, double val){
*data[i] = val;
}

double item(int i){
return *data[i];
}
};


int main(){
map mm(10);
mm.setitem(3,8);
std::cout << mm.item(3) << std::endl;

}
Last edited on
double * data[];
This doesn't compile.
sorry, I don't understand what you mean "by doesn't compile".
If I remove the destructor ~map(), the compiler does produce code that I can run. The output of the code is the text "8" as expected, which in turn suggests the value 8 gets stored somewhere.
Oh, it does, but compiler should at least warn. For example:
5:17: warning: ISO C++ forbids zero-size array 'data' [-Wpedantic]
 In function 'int main()':
8:29: warning: array subscript is above array bounds [-Warray-bounds] 
1
2
3
4
5
6
7
8
9
#include <iostream>

class map{
public:
  double * data[]; // warning: ISO C++ forbids zero-size array

  map(int size){
    *data = new double[size]; // warning: array subscript is above array bounds
  }

If something is forbidden ...

The syntax:
1
2
3
4
5
*data
// equals
*(data+0)
// equals
data[0]


Your 'data' is an array of pointers that has no elements. None. 0.

You do store a pointer into the first element of the array.
Into element that does not exist. That overwrites somebody else's memory.
The result is undefined behaviour.


Can you tell the precedence of these two operators?
1
2
3
4
5
6
7
*data[i]

// is it equal to
(*data)[i]

// or to
*(data[i])
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
27
28
29
30
31
32
33
34
35
#include <iostream>

struct map {

    double* data ;
    int sz ;

    explicit map( int size ) // validate that size is non-negative
        : data( size<0 ? throw "invalid arg" : new double[size]{} ), sz(size) {}

    ~map() { delete[] data ; }

    // non-copyable, non-assignable
    map( const map& ) = delete ;
    map& operator= ( const map& ) = delete ;

    void setitem( int i, double val ) {

        if( i < 0 || i >= sz ) throw "out of range" ; // sanity check
        data[i] = val ;
    }

    double item( int i ) const { // note: const

        if( i < 0 || i >= sz ) throw "out of range" ; // sanity check
        return data[i] ;
    }
};

int main() {

    map mm(10);
    mm.setitem(3,8);
    std::cout << mm.item(3) << '\n';
}

http://coliru.stacked-crooked.com/a/ec9ab15870e540ff
keskiverto thanks, I understand now

As to your quiz question, I don't know for sure but I going to make a hypothesis. My answer is : * data[i] is dereferencing an array of pointers and

* data [i] = * (data [i])

Two reasons for that:

1. It is the only option that would make sense if the array were multidimensional. if * data[i][j] was equivalent to (* data)[i][j] there would be no way for the compiler to know how to do the pointer arithmetic; so because multidimensional arrays exist, the [] construct must be inseparable from a named variable.

It follows that I am guessing that (* data) [i] is not a valid expression. If it were, it would be a door to the wilderness because if (* data)[i] is OK than 22343[i] or foo(...)[i] should also be.

There is probably no technical reason why these cannot be allowed (other than the multidimensional array issue) but the resulting code would be incredibly complicated to test, debug and maintain; and there was no reason to include such arcane syntax in the language.
Last edited on
@JLBorges:
Thanks for the detailed code.
I must admit I had to do some research to figure out what you are doing but I think I got it. You are definitely a back belt of C++ syntax!


Topic archived. No new replies allowed.