On Sat, Nov 14, 2009 at 09:32:20PM -0600, Peter Karman
wrote:> I want to set a variable number and type of ValueRangeProcessors at run
time
> based on a configuration file. But I seem to be running into (what I think
> is) a C++ scope issue.
>
> I tried just a simple test to see if I could add 5 VPs in a loop.
>
> Xapian::QueryParser qparser;
> Xapian::Query query;
>
> int vp = 0;
> while(vp < 5) {
> Xapian::StringValueRangeProcessor sproc(vp++);
> qparser.add_valuerangeprocessor(&sproc);
> }
>
> query = qparser.parse_query(myquery);
>
>
> That will compile, but when that code executes I get this error:
>
> pure virtual method called
> terminate called without an active exception
> Abort trap
>
> I *think* what's happening is that the sproc object goes out of scope
at the
> end of the while() loop and is GC'd by the time the qparser tries to
actually
> parse the query, so the qparser is trying to access a pointer that has been
> freed. But that's just a guess based on my limited knowledge of C++.
C++ doesn't use GC. The object sproc is precisely deleted at the end of the
block.
This isn't just an issue with C++. The Python bindings carefully keep
references for you, so this isn't an issue there. The Perl bindings
deliberately leak a reference, which isn't great, but avoids this issue
at least. The other bindings require you to keep the objects in scope.
There's a ticket about this issue:
http://trac.xapian.org/ticket/186
> What's the correct way to dynamically add a series of
ValueRangeProcessors?
In C++ you dynamically allocate with new:
Xapian::StringValueRangeProcessor * sproc;
sproc = new Xapian::StringValueRangeProcessor(vp++);
qparser.add_valuerangeprocessor(sproc);
To avoid leaking them (which isn't really a problem if this is a short lived
process like a CGI script, but would be for a query server), stick them into
a vector or similar and delete them later:
Xapian::QueryParser qparser;
Xapian::Query query;
vector<Xapian::ValueRangeProcessor*> vrps;
int vp = 0;
while(vp < 5) {
Xapian::StringValueRangeProcessor * sproc;
sproc = new Xapian::StringValueRangeProcessor(vp++);
qparser.add_valuerangeprocessor(sproc);
vrps.push_back(sproc);
}
query = qparser.parse_query(myquery);
// Once you're done with qparser:
vector<Xapian::ValueRangeProcessor*>::const_iterator i;
for (i = vrps.begin(); i != vrps.end(); ++i) {
delete *i;
}
Cheers,
Olly