значение std::map
является тяжелым объектом, потребляющим много ресурсов.Вставка такого элемента в std::map
ограничивает одну ненужную копию.Как устранить эти ненужные копии?
Вы правы в этом, и std::map::emplace
- единственное решение, которое мы имеем в настоящее время.Небольшое объяснение использования std::map::emplace
из cppreference.com приводится ниже:
Тщательное использование emplace
позволяет создавать новый элемент, избегая при этом ненужные операции копирования или перемещения .Конструктор нового элемента (т. Е. std::pair<const Key, T>
) вызывается с точно такими же аргументами, что и для emplace , пересылаемыми через std::forward<Args>(args)....
Это означает, что экземпляры класса a могут быть созданы на месте во время вставки карты (т. Е. вместо создания и копирования ) через std::map::emplace
, когда вы предоставляетеподрядчик в классе с точно такими же аргументами.И затем вам нужно использовать std::map::emplace
вместе с std::piecewise_construct
и std::forward_as_tuple
(при условии, что класс содержит большечем один член).
myMap.emplace(
std::piecewise_construct,
std::forward_as_tuple(/*key of map*/),
std::forward_as_tuple(/*all the members which you want to constrct in place*/)
);
Чтобы продемонстрировать приведенный выше случай, я создал небольшой пример кода, в котором элементы ClassA
будут построены на месте без вызова какой-либо специальной функции-члена.Чтобы убедиться, я отключил конструкторы default
, copy
и move
.
СМОТРИТЕ ЗДЕСЬ ЗДЕСЬ
#include <iostream>
#include <map>
#include <tuple>
class ClassA
{
int _val;
std::string _str;
public:
explicit ClassA(const int val, const std::string& str) : _val(val), _str(str)
{
std::cout << "A class: C'tor called...!\n";
}
// disable the following
ClassA() = delete;
ClassA(const ClassA&) = delete;
ClassA& operator=(const ClassA&) = delete;
ClassA(ClassA&&) = delete;
ClassA& operator=(ClassA&&) = delete;
};
class ClassB
{
ClassA _aObj;
public:
explicit ClassB(const int val, const std::string& str) : _aObj(val, str)
{
std::cout << "B class: C'tor called...!\n";
}
// disable the following
ClassB() = delete;
ClassB(const ClassB&) = delete;
ClassB& operator=(const ClassB&) = delete;
ClassB(ClassB&&) = delete;
ClassB& operator=(ClassB&&) = delete;
};
int main()
{
std::map<int, ClassB> myMap;
myMap.emplace(
std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(1, "some string")
);
return 0;
}
Вывод:
A class: C'tor called...!
B class: C'tor called...!
Обновление : С другой стороны,
Элемент может быть сконструирован даже если там уже есть элемент с ключом в контейнере, в этом случае вновь созданный элемент будет немедленно уничтожен.
Это означает, что вы ожидаете(или предположение):
" Я подозреваю, что какой-то метод в std::map
вставляет новый пустой элемент с некоторым ключом , но нетзначение , без вызова какого-либо конструктора для значения. Затем я могу переместить значение в свой собственный путь. "
- невозможно достичь вышеупомянутым std::map::emplace
способом.Как отметил @aschepler в комментариях, вы можете иметь карты с иногда (необязательными) ключами и без значений, используя функцию C ++ 17 std::optional
.
Для этого вам нужно сделать значения необязательными, как указано ниже, и, конечно, версия компилятора поддерживает C ++ 17 или новее.
std::map<Key, std::optional<Value>> myMap;
Теперь вы можете создавать объекты в любое время в коде и послекакое-то время вы можете переместить его в соответствующее значение ключа (т. е. запись).И последнее, но не менее важное: не забудьте указать стандартные значения для перемещения
СМ. ОБРАЗЕЦ КОДА ЗДЕСЬ
#include <optional>
class ClassA {
/* same as before*/
public:
// disable the copy c'tor
// enable move c'ntors
ClassA(ClassA&&) = default;
ClassA& operator=(ClassA&&) = default;
};
class ClassB {
/* same as before*/
public:
// disable the copy c'tor
// enable move c'ntors
ClassB(ClassB&&) = default;
ClassB& operator=(ClassB&&) = default;
};
int main() {
std::map<int, std::optional<ClassB>> myMap;
// created without calling any constructors
myMap.emplace(1, std::nullopt);
//later in the code
ClassB bObj{1, "JeJo"};
// again after..... move it to the required key-value
myMap[1] = std::move(bObj);
return 0;
}
Выход:
A class: C'tor called...!
B class: C'tor called...!