1

インスタンスの構築に非常に費用がかかるオブジェクトの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を使用して、同じキーを持つ要素が存在するかどうかを確認する必要がありますか?

4

2 に答える 2

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")));
于 2012-12-05T20:09:12.510 に答える
1

検索を使用して、オブジェクトがすでに存在する場合に作業を節約するために要素を挿入する必要があるかどうかを確認します。

悲しいことに、map::insertはコピーコンストラクターを何度も呼び出します。これにアクセスできず、c ++ 11を使用できる場合は、map::emplace_insertを確認してください。C ++ 03を使用する必要がある場合、IIRC Boostコンテナーには、内部でBoostmoveを使用してmoveセマンティクスをエミュレートするマップがあります。

于 2012-12-05T20:35:24.783 に答える