当std :: map :: insert找到元素时,它仍构造对象的实例.我怎么能阻止这个?

Sim*_*ott 1 c++ standard-library

我有一个std ::对象的映射,其实例构造起来非常昂贵.(在现实生活中,他们需要多次访问数据库.)

我想访问地图的一个元素,或者如果它不存在则创建它.这听起来像std :: map :: insert的工作,除了昂贵的对象不必要地构造,然后如果元素存在则抛弃.为了显示:

#include <iostream>
#include <map>
#include <string>

struct CexpensiveObject
{    
    CexpensiveObject(const char* args="default"):args_(args)
    {
        std::cout << "Constructor: CexpensiveObject(" << args << ")" << std::endl;
    }
    CexpensiveObject( const CexpensiveObject& other )
    {
        std::cout << "Copy Constructor: CexpensiveObject other.args_ = " << other.args_ << "." << std::endl;
        args_ = other.args_;
    }
    ~CexpensiveObject()
    {
        std::cout << "Destructor: CexpensiveObject args_ = " << args_ << "." << std::endl;
    }
    const char* args_;
};

// entry point
int main() 
{
    typedef std::map<std::string, CexpensiveObject> mymaptype;   
    mymaptype mymap;
    std::pair<mymaptype::iterator, bool> insertionResult;

    std::cout << "First insertion" << std::endl;
    insertionResult = mymap.insert( mymaptype::value_type( "foobar", CexpensiveObject("first") ) );
    std::cout << "Was it inserted? " << (insertionResult.second?"yes":"no") << std::endl;

    std::cout << "Second insertion" << std::endl;
    insertionResult = mymap.insert( mymaptype::value_type("foobar", CexpensiveObject("second") ) );
    std::cout << "Was it inserted? " << (insertionResult.second?"yes":"no") << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

结果:

First insertion
Constructor: CexpensiveObject(first)
Copy Constructor: CexpensiveObject other.args_ = first.
Copy Constructor: CexpensiveObject other.args_ = first.
Destructor: CexpensiveObject args_ = first.
Destructor: CexpensiveObject args_ = first.
Was it inserted? yes
Second insertion
Constructor: CexpensiveObject(second)
Copy Constructor: CexpensiveObject other.args_ = second.
Destructor: CexpensiveObject args_ = second.
Destructor: CexpensiveObject args_ = second.
Was it inserted? no
Destructor: CexpensiveObject args_ = first.
Run Code Online (Sandbox Code Playgroud)

复制和销毁的次数比我预期的要多,但关键的是构造一个实例CexpensiveObject,如果ma中存在具有相同键的元素,则抛弃它.

我是否滥用std :: map :: insert,或者我必须使用std :: map :: find来检查在实例化CexpensiveObject实例之前是否存在具有相同键的元素?

Rob*_*edy 9

它是insert在你打电话之前建造的CexpensiveObject("second").你传递了无关的物体!(然后它被复制,因为value_type传递给insert.)

而不是insert,使用find.如果您在所需的键上找到该项目,那么您就完成了.如果没有,那么插入它.

auto it = mymap.find("foobar");
if (it == mymap.end())
  mymap.insert(mymaptype::value_type("foobar", CexpensiveObject("second")));
Run Code Online (Sandbox Code Playgroud)