0

I am trying to have an array as part of a class. The array should be the variable size. In my code, the array should be given contents by some function to a variable size and after that treated just as a member of a class. My code isn't running and I was able to boil my problem down to a couple of lines of code.

In this example, I am holding the array in a pointer "dptr" so it can be initialized by a function to variable size and then accessed as a class member.

After I gave the pointer contents in a void I can call it exactly once, after that all I get when accessing it is some kind of weird, almost random, number.

class x 
{
public:
   double* dptr;

void void_()
   {
       double d[] = { 2., 3., 4. };
       dptr = d;
   }
};


int main() 

{
   x x_;
   x_.void_();

   int index = 0;
   std::cout << x_.dptr[index] << std::endl; // works perfectly fine for any index ( outputs 2 )

   std::cout << x_.dptr[index] << std::endl; // outputs something random ( outputs 6.95241e-310 )
}

I guess that after the void ends the destructor of the double "d" is called and the contents the pointer points to are deleted.

Is there some way of solving that problem by, for example, not allowing the destructor to be called?

jakob
  • 147
  • 1
  • 7
  • Take the easy route, use a vector instead. – john Dec 26 '20 at 16:20
  • Take a look at https://stackoverflow.com/questions/4570366/how-to-access-a-local-variable-from-a-different-function-using-pointers to understand what is going on with the pointer. But switching to a vector is the best route to fix this. – Michael Albers Dec 26 '20 at 16:24
  • 3
    Once `void_` returns, its local array, `d` gets destroyed. The fact that a pointer to the array is saved somewhere else is immaterial, it's still destroyed, and referencing that pointer, from that point, [results in demons flying out of your nose](http://www.catb.org/jargon/html/N/nasal-demons.html). The reason you're seeing "weird" random numbers is because this is what nasal demons do. And no, there is no way to prevent `d` from getting destroyed, C++ does not work this way. – Sam Varshavchik Dec 26 '20 at 16:25
  • 1
    *"works perfectly fine"*. in fact you are already in UB land, and it **seems** to work (possible output of UB). – Jarod42 Dec 26 '20 at 16:26

2 Answers2

4

The clean way would be to use a std::vector and initialize the member when the constructor is called:

struct x {
    std::vector<double> d;
    x() : d{2.,3.,4.} {}
};

The way to avoid a descrutor getting called is to dynamically create the array. However, in that case x should to follow the rule of 5.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
-2

Nope, you're stuck with using a dynamically allocated pointer and adding a destructor to the class:

class x 
{
public:
   double* dptr;

x()
  {
    dptr = nullptr;
  }
x(const &x) = delete;
operator=(const &x) = delete;

void void_()
   {
       double d[] = new double[3]
       d[0] = 2.;
       d[1] = 3.;
       d[2] = 4.; 
       dptr = d;
   }
 ~x() 
   {
       if(dptr != nullptr) {
          delete[] dptr;
       }
   }
};

But if you're trying to allocate an array in this way to do any real work, please consider using std::vector instead. Then all the internals are handled for you and you don't have to mess with pointers.

Brad
  • 2,261
  • 3
  • 22
  • 32
  • Forgive me, I am not familiar with the Rule of 5... do you mean that I should explicitly mark the the copy constructor, default constructor, etc as `= delete`? – Brad Dec 26 '20 at 16:33
  • The code in the destructor should be `delete [] dptr;`. It was created with `new[]`, so it must be destroyed with `delete[]`. – Pete Becker Dec 26 '20 at 16:36
  • Answer updated with both suggestions - does it look OK now? – Brad Dec 26 '20 at 16:40
  • Thanks for the feedback folks! Learned some new stuff today. – Brad Dec 26 '20 at 16:45
  • Your class isn't constructible. After you fix that you have another problem: you have UB in the destructor if `void_` isn't called on the object. – bolov Dec 26 '20 at 16:47
  • 1
    Your edit added an unnecessary test. `operator delete` and `operator delete[]` understand null pointers. You don’t need `if (dptr != nullptr)` in the destructor. – Pete Becker Dec 26 '20 at 19:06