繁体   English   中英

当std :: map :: insert找到元素时,它仍会构造该对象的实例。 我该如何阻止呢?

[英]when std::map::insert finds the element, it still constructs an instance of the object. How can I stop this?

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

我想访问地图的某个元素,或者如果不存在则创建它。 这听起来像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;
}

结果:

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.

复制和销毁比我预期的要多,但是关键是要构造一个实例CexpensiveObject,然后如果在ma中存在具有相同键的元素,则将其丢弃。

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

它是在调用CexpensiveObject("second")甚至insert之前构造的。 您正在传递无关的对象! (然后在将value_type传递给insert其复制。)

代替insert ,使用find 如果您在所需的键处找到该项目,那么您就完成了。 如果不是, 则将其插入。

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

使用find检查是否应插入元素以节省一些工作(如果对象已存在)。

可悲的是map :: insert多次调用您的副本构造函数。 如果无法胜任,并且可以使用c ++ 11,请查看map :: emplace_insert。 如果必须使用C ++ 03,则IIRC boost容器具有一个映射,该映射在内部使用Boost移动来模拟移动语义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM