std::map 中的最佳创建新空元素
Optimal creation new empty element in std::map
要插入新元素 std::map
需要存在 std::pair
对象。
我没有找到另一种方法来将新元素添加到 std::map
而无需构造这样的 std::pair
对象。
但是假设 std::map
值是一个消耗大量资源的重对象。将这样的元素插入 std::map
限制了一个不必要的副本。在这种情况下
我有一些对象 X 需要直接复制到 std::map
,std 作者限制我分两步执行此复制:
- 复制 X->
std::pair
- 复制对象对 ->
std::map
插入位置。
如何删除这些不需要的副本?实施 Move 构造函数无法解决我的问题 - 副本仍然存在。
我怀疑 std::map
中的某些方法插入了一个新的空元素,其中包含一些键但没有值,而没有为该值调用任何构造函数。然后我可以以我自己的方式移动价值。
但是我在 std::map
!
中没有找到这样的方法
您正在寻找std::map::emplace
the std::map
value is a heavy object consuming a lot of resources. Inserting such element into std::map
constraints one unnecessary
copy. How to eliminate these unneeded copy?
你说得对,std::map::emplace
is the only solution what we have available now. A small explanation about the use of std::map::emplace
from cppreference.com 如下:
Careful use of emplace
allows the new element to be constructed while
avoiding unnecessary copy or move operations. The constructor of the
new element (i.e. std::pair<const Key, T>
) is called with exactly the
same arguments as supplied to emplace, forwarded via
std::forward<Args>(args)....
这意味着 class-实例可以在地图插入时就地构建(即,而不是构建和通过 std::map::emplace
复制 ),当您向 class 中的承包商提供完全相同的参数时。然后,您需要使用 std::map::emplace
和 std::piecewise_construct
and std::forward_as_tuple
(假设 class 包含多个成员)。
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...!
更新:另一方面,
The element may be constructed even if
there already is an element with the key in the container, in which
case the newly constructed element will be destroyed immediately.
这意味着,您的期望(或假设):
" 我怀疑 std::map
中的某些方法插入了一个新的空元素 一些键 但是没有值,没有为该值调用任何构造函数。然后我可以以我自己的方式移动该值。 "
是不可能实现的,通过上面提到的std::map::emplace
方式。正如@aschepler 在评论中指出的那样,通过使用 C++17 功能 std::optional
.[=43=,您可以拥有带有有时(可选)键但没有值的映射]
为此,您需要将值设为可选,如下所示,当然编译器版本支持 C++17 或更高版本。
std::map<Key, std::optional<Value>> myMap;
现在您可以随时在代码中构造一个对象,过一会儿,您可以将它移动到适当的键值(即条目)。最后但同样重要的是,不要忘记提供 default move-c'ntors
#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...!
要插入新元素 std::map
需要存在 std::pair
对象。
我没有找到另一种方法来将新元素添加到 std::map
而无需构造这样的 std::pair
对象。
但是假设 std::map
值是一个消耗大量资源的重对象。将这样的元素插入 std::map
限制了一个不必要的副本。在这种情况下
我有一些对象 X 需要直接复制到 std::map
,std 作者限制我分两步执行此复制:
- 复制 X->
std::pair
- 复制对象对 ->
std::map
插入位置。
如何删除这些不需要的副本?实施 Move 构造函数无法解决我的问题 - 副本仍然存在。
我怀疑 std::map
中的某些方法插入了一个新的空元素,其中包含一些键但没有值,而没有为该值调用任何构造函数。然后我可以以我自己的方式移动价值。
但是我在 std::map
!
您正在寻找std::map::emplace
the
std::map
value is a heavy object consuming a lot of resources. Inserting such element intostd::map
constraints one unnecessary copy. How to eliminate these unneeded copy?
你说得对,std::map::emplace
is the only solution what we have available now. A small explanation about the use of std::map::emplace
from cppreference.com 如下:
Careful use of
emplace
allows the new element to be constructed while avoiding unnecessary copy or move operations. The constructor of the new element (i.e.std::pair<const Key, T>
) is called with exactly the same arguments as supplied to emplace, forwarded viastd::forward<Args>(args)....
这意味着 class-实例可以在地图插入时就地构建(即,而不是构建和通过 std::map::emplace
复制 ),当您向 class 中的承包商提供完全相同的参数时。然后,您需要使用 std::map::emplace
和 std::piecewise_construct
and std::forward_as_tuple
(假设 class 包含多个成员)。
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...!
更新:另一方面,
The element may be constructed even if there already is an element with the key in the container, in which case the newly constructed element will be destroyed immediately.
这意味着,您的期望(或假设):
" 我怀疑 std::map
中的某些方法插入了一个新的空元素 一些键 但是没有值,没有为该值调用任何构造函数。然后我可以以我自己的方式移动该值。 "
是不可能实现的,通过上面提到的std::map::emplace
方式。正如@aschepler 在评论中指出的那样,通过使用 C++17 功能 std::optional
.[=43=,您可以拥有带有有时(可选)键但没有值的映射]
为此,您需要将值设为可选,如下所示,当然编译器版本支持 C++17 或更高版本。
std::map<Key, std::optional<Value>> myMap;
现在您可以随时在代码中构造一个对象,过一会儿,您可以将它移动到适当的键值(即条目)。最后但同样重要的是,不要忘记提供 default move-c'ntors
#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...!