1

C++ クライアント ライブラリを使用し、cursor->next() から返された BSONObj オブジェクトを保持している場合、後続の新しいクエリ (同じ接続を使用) は何らかの形でそのオブジェクトを破壊しますか? 私の理解では、それはスマートポインターであり、それへの最後の参照が範囲外になるまで存続します。ただし、実際には、後続のクエリがオブジェクトを破壊しているように見えることがわかります。新しいクエリがトラバースされた後、オブジェクトの hasField/getField メソッドにアクセスすると、セグメンテーション違反が発生します。

関連するコードは次のとおりです。

BSONObj DB::getmsg        
(                         
    const string &oid     
)                         
{                         
    BSONObj query = BSON("_id" << OID(oid));
    auto_ptr<DBClientCursor> cursor = c.query("nsdb.messages", query);
    if (cursor->more())                                               
        return cursor->next();                                        
    throw Exception("could not find object %s", oid.c_str());         
}                                                                     

void DB::getchildren
(                   
    const string &oid,
    vector<BSONObj> &children
)                            
{                            
    BSONObj query = BSON("parent" << oid);
    BSONObj fields = BSON("_id" << 1);    
    auto_ptr<DBClientCursor> cursor =     
        c.query("nsdb.messages", query, 0, 0, &fields);
    while (cursor->more())                             
        children.push_back(cursor->next());            
}                                                      

void DB::message
(               
    const string &oid,
    string &str,      
    bool body         
)                     
{                     
    connect();        
    BSONObjBuilder response;
    try                     
    {                       
        BSONObj n = getmsg(oid);
        response.append("message", n);
        vector<BSONObj> children;     
        getchildren(oid, children);   
        if (children.size() > 0)      
        {                             
            BSONArrayBuilder a;       
            vector<BSONObj>::iterator i;
            for (i = children.begin(); i != children.end(); i++)
            {                                                   
                if (!(*i).isEmpty() && (*i).hasField("_id"))    
                {                                               
                    string child = (*i).getField("_id").__oid().str();
                    a.append("http://127.0.0.1:12356/lts/message/" + child);
                }                                                           
            }                                                               
            if (a.len() > 0)
                response.append("children", a.done());
        }
        if (body)
        {
            string fname;
            if (n.hasField("fname"))
                fname = n.getField("fname").str();
            if (fname.empty())
            {
                throw Exception("no fname field in message record %s",
                    n.jsonString().c_str());
            }
            auto_mmapR<const void *, int> m(fname);
            response.appendBinData("body", m.size(), BinDataGeneral,
                m.get());
        }
        str = response.obj().jsonString();
    }
    catch (const DBException &x)
    {
        throw Exception("%s", x.what());
    }
}

パーツを移動した場合:

string fname;
if (n.hasField("fname"))
    fname = n.getField("fname").str();

getchildren(...) が呼び出される前に、fname フィールドがメッセージから正しく取得されます。それ以外の場合は、「メッセージ レコードに fname フィールドがありません」という例外がスローされます。

4

1 に答える 1