0

I have an std::vector containing elements of class BoundingBox (std::vector<BoundingBox>, which I call BB_Array). First, i create this vector using a function that I will simplify here:

BB_Array* Detector::generateCandidateRegions(BB_Array* candidates){
    BB_Array* result = new BB_Array(); // without new here, i get segmentation fault
    BB_Array tempResult;

    // apply tests to candidates and add the good ones to tempResult ... 
    // ... using tempResult.push_back((*candidates)[i]);

    for (int i=0; i < tempResult.size(); i++){
        // apply more tests to tempResult[i] and, if necessary, add it...
        // ... using result->push_back(maxCandidate); 
    }

    return result;
}

This function works and there is no memory leak according to valgrind. Now, that function needs to be applied once (for performance) and I need a function to add elements to it. This is where I'm having problems. The way I'm doing it now is:

BB_Array* Detector::addCandidateRegions(BB_Array* candidates) {
    BB_Array* result = new BB_Array();
    BB_Array sparseDetections;

    // apply tests and add stuff to sparseDetections using... 
    // ... sparseDetections.push_back((*candidates)[i]);

    for (int i=0; i < sparseDetections.size(); i++){
        // add things to result using result->push_back()
    }

    return result;
}

This second function gave me the candidates I need to add to the vector created before:

BB_Array *newCandidates = addCandidateRegions(...);
if (newCandidates->size() > 0){
   denseCandidates->insert(denseCandidates->end(), newCandidates->begin(), newCandidates->end());
   delete newCandidates;
}

Now, this is causing heap corruption and the program crashes after something like 500 images. So what am I doing wrong? Is there a better way of doing this?

I also have a function to remove elements from the vector afterwards, but I think I can figure it out once I get the adding part done.

EDIT: forgot to put the error message:

*** Error in `./C_Arnoud_Calibrated_Detector': malloc(): smallbin double linked list corrupted: 0x0000000001f4eed0 ***
Aborted (core dumped)

doesn't happen at the same iteraction every time and, sometimes, I get a segmentation fault instead.

EDIT 2: I fixed it today. No more heap problems. I was probably tired and used the wrong index in one specific scenario, so out of thousands of iteractions sometimes unexpected things happened and it broke everything. Thanks everybody for the suggestions and, if you use an object detector, it is now safe to use =).
https://github.com/CArnoud/C_Arnoud_Calibrated_Detector

trincot
  • 317,000
  • 35
  • 244
  • 286
  • 3
    Just stop using new/delete. There is no need for it here. Pass the vectors by (const) reference to your function and return them by value. – D Drmmr Mar 14 '15 at 14:05
  • 1
    Can you try extracting and posting the minimal, compiling example that misbehaves? I don't see anything causing memory problems at this level of abstraction. (Delete inside if in the last sample is a little suspicious, but with the right code around the sample, it will work ok). – sbarzowski Mar 14 '15 at 14:12
  • @DDrmmr if I take away the new, i get a segmentation fault error – Charles Arnoud Mar 14 '15 at 14:15
  • 5
    @Charles: Don't just take away `new` -- completely change over the API and implementation so it's all in terms of values and references. –  Mar 14 '15 at 14:30
  • Does your BB_Array destructor delete any memory? If you copy one, will it copy internal pointers? That's a common but disastrous combination. – sje397 Mar 14 '15 at 14:39
  • @sbarzowski changing the placement of delete to outside the if, let's the program run to it's end but I get this error at the end: munmap_chunk(): invalid pointer: 0x0000000000a053e0 *** Aborted (core dumped) – Charles Arnoud Mar 14 '15 at 14:46
  • @Hurkyl could you give me an example? I didn't understand. – Charles Arnoud Mar 14 '15 at 14:48
  • @sje397 I actually didn't create a destrutor for BB_Array. – Charles Arnoud Mar 14 '15 at 14:49

1 Answers1

1

First off, do you use a compiler that is older than you ?

Yes -> Stop doing that. Why are you hating yourself so much ?

No -> Good news, everything your professors have "taught" you about C++ is wrong and false. Compilers are very good at return value optimization. Make your functions return values, they will be moved and not copied, which is essentially free, and stop this new/delete/raw pointer madness in application code.

BB_Array Detector::generateCandidateRegions(BB_Array& candidates){
    BB_Array result; // Use values.
    BB_Array tempResult;

    // Do whatever the heck you want.

    for (int i=0; i < tempResult.size(); i++){
        // apply more tests to tempResult[i] and, if necessary, add it...
        // ... using result.push_back(maxCandidate); 
    }

    return result;
}

BB_Array newCandidates = addCandidateRegions(...);
if (newCandidates.size() > 0){
   denseCandidates.insert(denseCandidates.end(), newCandidates.begin(),
                          newCandidates.end());
}

Easy memory management, easy life.

Félix Cantournet
  • 1,941
  • 13
  • 17
  • Oh and how would I call the generateCandidateRegions function? – Charles Arnoud Mar 14 '15 at 17:36
  • sadly, it didn't fix my problem. but it is a great suggestion to make the code clearer. if i could like, i would. – Charles Arnoud Mar 14 '15 at 18:46
  • @Charles Arnoud you would call the generateCandidateRegions with a value. Could you post a more complete code sample ? or do you have a link to your git repository or something similar ? – Félix Cantournet Mar 15 '15 at 13:16
  • the repository is: https://github.com/CArnoud/C_Arnoud_Calibrated_Detector, and the problem is in the Detector.cpp file. but, honestly, it is a very long file and it would probably take you a long time to debug it. – Charles Arnoud Mar 15 '15 at 22:19
  • so i would call generateCandidateRegions(denseCandidates) regardless of if the template was generateCandidateRegions(BBArray candidates) or generateCandidateRegions(BB_Array& candidates)? Because thats what im doing now. – Charles Arnoud Mar 16 '15 at 13:09
  • Yes. it's a pass by reference call. You call the function with a value, and the reference to that value is passed to the body of the function. – Félix Cantournet Mar 16 '15 at 13:18
  • Thank you Félix, so if that's not my problem I'll keep searching. I would like your comment if I could. – Charles Arnoud Mar 16 '15 at 13:21
  • 1
    I'm not aware of `valgrind` being usable with any compilers that would be older than OP ! – M.M Mar 16 '15 at 14:23
  • @MattMcNabb Yes i might have gotten carried away. The general reasonning still stands. – Félix Cantournet Mar 16 '15 at 14:27