I know there is already at least a dozen valgrind reports invalid read questions, but please bear with me cause I really don’t know how to help myself so I’m asking for yours.
I am writing a wrapper for OpenCV feature detection and feature description modules (I want to be able to implement my own feat detection / extraction at some point). Because of that, I can not operate directly on OpenCV datatypes.
So, when extracting descriptors from features, I store them as std::vector <std::vector <double> > instead of cv::Mat. I have this piece of code where I first calculate the descriptors and then convert them from one notation to another:
// private
void CVDescriptor::calculateDescriptors(std::vector <cv::KeyPoint> &feats){
this->feats = &feats;
this->descCalc->compute(*(this->image), feats, this->desc);
this->calculated = true;
}
// public
void CVDescriptor::calculateDescriptors
(std::vector< std::vector< double > >& desc,
std::vector< cv::KeyPoint >& feats){
if (!this->calculated)
this->calculateDescriptors(feats);
assert(this->calculated);
const double *temp;
desc.clear();
desc.reserve(this->desc.rows);
for (int i=0, szi = this->desc.rows; i < szi; ++i){
temp = this->desc.ptr<double>(i);
// this line is the problem
desc.push_back(std::vector<double>(temp, temp+(this->desc.cols)));
// .
// /|\
// |
}
assert(desc.size() == this->desc.rows);
assert(desc[0].size() == this->desc.cols);
return;
}
Here are the types of my member variables, and I’ve checked and written where I initialize them (just to avoid confusion):
std::vector <cv::KeyPoint> *feats
cv::Mat *image;
// it is set just before calling calculateDescriptors(desc, feats)
cv::Mat desc;
bool calculated; // set in the only constructor
Here’s the OpenCV documentation for cv::DescriptorExtractor::compute. From what I can see, each calculated descriptor should be one row in cv::Mat, and should have as much components as the matrix has columns.
I’m suspecting memory leaks at some places in my code, so I’ve run it through Valgrind. The first thing it reports is Invalid read of size 1 on the line marked with a big arrow in my code excerpt. As far as I can see, it is reporting it only twice per call to CVDescriptor::calculateDescriptors(..), not in every iteration of the for loop.
Can anyone see anything obviously wrong with my copying code? Or has any other ideas how this might be happening?
I can provide additional information if needed, but I’ve tried to put all the relevant code here (as my project is pretty big). Thank you all in advance (and I’m sorry for the lengthy question)…
I added a printout of the starting and ending addresses of the memory block being copied in every iteration, and that revealed the problem. Excerpt from the printout:
In every iteration I was accidentally trying to copy two rows of the
cv::Matat once, because I was accessing it throughdoublepointers, while the data stored wasfloat.Declaring
tempas aconst float *temp;and changing thetempassignment indoes the trick.