我的程序中有大量大型对象。它们当前存储在带有客户比较函子的
std::set
中。该集合一开始是空的,我不断地将物体放入其中。我还定期“消耗”一组物体的一端。
在程序执行过程中的几个(2-10)个关键点,我可能想更改这些对象的排序,并继续按照新的顺序放置和使用它们。我通常有三种可能的顺序,并且不断在它们之间切换。
我希望在不复制大型对象的情况下进行求助,而是移动它们。
考虑以下示例:
#include <iostream>
#include <set>
#include <utility>
struct S {
int a;
S(int a) : a{a} { std::cout << "Constructor\n"; }
S(const S& s) : a{s.a} { std::cout << "Copy constructor\n"; }
S(S&& s) : a{std::exchange(s.a, 0)} { std::cout << "Move constructor\n"; }
S& operator=(const S& s) { std::cout << "Copy assignment\n"; return *this = S(s); }
S& operator=(S&& s) { std::cout << "Move assignment\n"; std::swap(a, s.a); return *this; }
};
int main() {
auto order = [] (const S& s1, const S& s2) -> bool { return s1.a < s2.a; };
auto inver = [] (const S& s1, const S& s2) -> bool { return s2.a < s1.a; };
std::set<S, decltype(order)> set1;
set1.emplace(1);
set1.emplace(3);
set1.emplace(2);
for(auto&& s : set1) {
std::cout << s.a << " ";
}
std::cout << "\n";
std::set<S, decltype(inver)> set2{set1.begin(), set1.end()};
for(auto&& s : set2) {
std::cout << s.a << " ";
}
std::cout << "\n";
return 0;
}
打印以下输出:
Constructor
Constructor
Constructor
1 2 3
Copy constructor
Copy constructor
Copy constructor
3 2 1
是否可以使用移动构造函数而不是复制构造函数?如何? 如果这是不可能的,那么解决我的问题的好策略是什么? 我是否应该将对象保留在不会使指针无效并具有恒定时间直接访问的数据结构中(例如从未调整大小的大型向量 - 或者,请建议更合适的结构)并且仅对它们的索引进行排序?
听起来您可以使用
set::extract
从第一组中删除项目,并使用 set::insert
的 节点句柄重载将它们添加到第二组中。在此过程中不会复制或移动任何
S
。
像这样
#include <set>
#include <iostream>
#include <utility>
struct S {
int a;
S(int a) : a{a} { std::cout << "Constructor\n"; }
S(const S& s) : a{s.a} { std::cout << "Copy constructor\n"; }
S(S&& s) : a{std::exchange(s.a, 0)} { std::cout << "Move constructor\n"; }
S& operator=(const S& s) { std::cout << "Copy assignment\n"; return *this = S(s); }
S& operator=(S&& s) { std::cout << "Move assignment\n"; std::swap(a, s.a); return *this; }
};
int main() {
auto order = [] (const S& s1, const S& s2) -> bool { return s1.a < s2.a; };
auto inver = [] (const S& s1, const S& s2) -> bool { return s2.a < s1.a; };
std::set<S, decltype(order)> set1;
set1.emplace(1);
set1.emplace(3);
set1.emplace(2);
std::set<S, decltype(inver)> set2;
// extract the first node
auto h = set1.extract(set1.begin());
// add to the second set
set2.insert(std::move(h));
for(auto&& s : set1) {
std::cout << s.a << " ";
}
std::cout << "\n";
for(auto&& s : set2) {
std::cout << s.a << " ";
}
std::cout << "\n";
return 0;
}
输出
Constructor
Constructor
Constructor
2 3
1
如您所见,没有任何内容被复制或移动。