когда std :: map :: insert находит элемент, он все еще создает экземпляр объекта. Как я могу остановить это?

У меня есть 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.

Там больше копирования и уничтожения, чем я ожидал, но критически важно, чтобы экземпляр CexорогоObject создавался и затем выбрасывался, если в ма существует элемент с тем же ключом.

Я неправильно использую std :: map :: insert, или мне нужно использовать std :: map :: find, чтобы проверить, существует ли элемент с тем же ключом, прежде чем я создаю экземпляр CexblyObject?

1

Решение

Он построен еще до того, как 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")));
9

Другие решения

Используйте find, чтобы проверить, должен ли элемент быть вставлен, чтобы сэкономить некоторую работу, если объект уже существует.

К сожалению, map :: insert часто вызывает ваш конструктор копирования. Если это недопустимо, и вы можете использовать c ++ 11, взгляните на map :: emplace_insert. Если вы должны использовать C ++ 03, IIRC буст контейнер есть карта, которая использует внутренне Ускорить движение подражать семантике ходов.

1

По вопросам рекламы [email protected]