0

I apologize for the vague title of my question. I don't know a better way to phrase it. I've never asked a Stack Overflow question before but this one has me completely stumped.

A method in class Chunk uses the Eigen linear algebra library to produce a vector3f, which is then mapped to a C-style array with the following.

ColPivHouseholderQR<MatrixXf> dec(f);
Vector3f x = dec.solve(b);

float *fit = x.data();
return fit;

This array is returned and accessed in the main function. However, whenever I attempt to print out a value from the pointer, I get completely different results. A sample is below.

Chunk test = Chunk(CHUNK_SIZE, 0, 0, 1, poBand);
float* fit = test.vector;  // Should have size 3
std::cout << fit[0] << std::endl; // Outputs 3.05 (correct)
std::cout << fit[0] << std::endl; // Outputs 5.395e-43
std::cout << fit[0] << std::endl; // Outputs 3.81993e+08

What makes this issue even more perplexing is that the incorrect values change when I end the lines with "\n" or ", ". The first value is always the expected value, no matter whether I print index 0, 1, or 2.

I have tried dynamically allocating memory for the fit variable, as well as implementing the code on this answer, but none of it changes this functionality.

Thank you in advance for any guidance on this issue.

Minimally Reproducible Example:

float* getVector() {
    Eigen::Vector3f x;
    x << 3, 5, 9;

    float* fit = x.data();
    return fit;
}

int main(void) {
    float* fit = getVector();

    std::cout << fit[0] << std::endl;
    std::cout << fit[0] << std::endl;
    std::cout << fit[0] << std::endl;
}
  • 1
    Can you post the necessary parts of the implementation of Chunk? – SuperStormer Jun 11 '22 at 21:01
  • @SuperStormer I'm positive it is not an issue with Chunk, as each index of fit is initially correct, before changing. However, if it helps here are the main parts of Chunk.` – Jackie Carson Jun 11 '22 at 21:07
  • 2
    Smells very much like undefined behavior, since the variable is not changing between outputs. – Mark Ransom Jun 11 '22 at 21:07
  • What is the type of `Chunk.vector`? – Mark Ransom Jun 11 '22 at 21:09
  • @MarkRansom it returns a float* – Jackie Carson Jun 11 '22 at 21:09
  • What is `x.data()` ? Seems like a local variable issue. – Jane Doe Jun 11 '22 at 21:11
  • 1
    Please read how to provide a [mre]. Anyway, your problem likely is that you are returning a pointer to data which does not exist after the function exits, which causes UB. – chtz Jun 11 '22 at 21:11
  • You say, in response to Mark's question about `vector`, that it "returns a `float*`". But you aren't ***calling*** it. If it's a function, then you need parentheses in `float* fit = test.vector();`. – Adrian Mole Jun 11 '22 at 21:13
  • `return x.data();` would create a dangling pointer, but how does that fit into the code that does the output? Without something complete enough to reproduce the error, we're just pointing out things that are wrong and hoping one of them is the cause of your current symptom. – JaMiT Jun 11 '22 at 21:14
  • @AdrianMole the method that returns the float* is called in the constructor of the class. is that still an issue? – Jackie Carson Jun 11 '22 at 21:15
  • 1
    Likely an equivalent issue: [Weird output when converting from string to const char*](https://stackoverflow.com/questions/44055955/) (but again, the code is too incomplete to be sure this is the cause of your symptom rather than some other undefined behavior). – JaMiT Jun 11 '22 at 21:20
  • @JaMiT I have posted a reproducible example now. Thank you for all the help – Jackie Carson Jun 11 '22 at 21:22

1 Answers1

3

You create the vector x in the function on the stack. It is destroyed after the function exited. Hence your pointer is invalid.

Here an example with shared_ptr

ColPivHouseholderQR<MatrixXf> dec(f);
Vector3f x = dec.solve(b);
shared_ptr<float> fit(new float[3],std::default_delete<float[]>());
memcpy(fit,x.data(),sizeof(float)*3);
return fit;

Another possible way is

ColPivHouseholderQR<MatrixXf> dec(f);
Vector3f x = dec.solve(b);
return x;
kmodexc
  • 140
  • 4
  • While you are probably correct, the code is not returning `x` but rather `x.data()` which very well could be some heap allocated data and the code would be valid. – Jane Doe Jun 11 '22 at 21:15
  • @JaneDoe even then it will be removed in the destructor of x – kmodexc Jun 11 '22 at 21:17
  • I'm very sorry- I'm still a beginner to C++ but how do I create a pointer thats actually saved into memory in this case? – Jackie Carson Jun 11 '22 at 21:17
  • @Marius Destructors don't automagically clean up heap allocated memory. The code doesn't show that anywhere. It's not clear from the code that `Vector3f ` is RAII class. – Jane Doe Jun 11 '22 at 21:18
  • @JaneDoe `Vector3f` will never heap-allocate its data, it is essentially like a `std::array` (with different methods/operators, of course). – chtz Jun 11 '22 at 21:20
  • I would create a private variable in the chunk class. Then you need to move it with memcpy. Another way can be shared_pointer. It really depends and i dont know about the code around this. – kmodexc Jun 11 '22 at 21:23
  • @JaneDoe Well, in the code sample that the OP has now added, the `x` ***is*** a local object that will be destroyed when the containing function returns. – Adrian Mole Jun 11 '22 at 21:23
  • @JaneDoe then you would have a memory leak which is not good at all. – kmodexc Jun 11 '22 at 21:24
  • The fact that the output changes between the calls shows that, indeed, the pointed-to data was on the stack, and that stack location is being used by the output calls themselves. – Adrian Mole Jun 11 '22 at 21:26
  • You could just make `getVector()` return the `Eigen::Vector3f` (returning small objects by value is not too expensive, especially if the function can get inlined). – chtz Jun 11 '22 at 21:27
  • @chtz I really should have done that to be honest, I think I can still do it without editing my code too mcuh – Jackie Carson Jun 11 '22 at 21:29
  • @JackieCarson returning C-style pointers will be a nightmare to maintain, even if you get it to work somehow. You would need to keep track of who "owns" the data and who is responsible for allocating/deallocating. So yes, refactor your code while it is still "small". – chtz Jun 11 '22 at 21:33