过度移动构造函数
move constructor overkill
我有一个类,它包含一个指针,指向一大块分配的内存和许多基元类型成员。我正在考虑移动构造函数,并认为这是一个使用构造函数的绝佳机会。显然,指针应该移到idk上,如果这是基元的好主意的话。
以下是该类的一个人为示例:
class Foo {
private:
long m_bar = 1;
/* 20+ similar members */
};
为了使它们能够移动,必须对它们进行动态分配。
class Foo {
public:
Foo(Foo && rhs) : m_bar(rhs.m_bar) { rhs.m_bar = nullptr; }
~Foo() { delete m_bar; }
private:
long *m_bar = new long{1};
};
我的问题是,在堆上分配的开销会抵消移动语义带来的性能提升吗?
如果有什么不同的话,我相信像这样的堆分配每个成员最终会更慢。除了最初的堆分配(仅在构造时执行)之外,持有指向堆上许多小的、不连续的数据成员的指针与CPU缓存策略配合不好。
有些类移动得很好,因为它们分配了大量内存(例如std::string)。在您的情况下,移动每个指针的成本与移动较小的数据类型的成本一样高。我认为这样做更快的唯一方法是,将较小的数据成员封装在堆分配的类/结构中(可能持有一个unique_pointer),并通过单个指针的移动来移动所有这些成员。
也就是说,这很可能是一个过早优化的情况。您可能想让代码按原样运行,并确定为类实现更复杂的移动语义确实可以帮助代码的性能。
Move语义只有在移动对象比复制对象快的情况下才会更快。在您的示例中,情况并非如此。复制long应该与将指针复制到long的速度相同。通过动态分配每个成员来添加移动语义几乎肯定会减慢速度,而不是加快速度。
可能导致更快移动构造函数的是使用PIMPL习惯用法。您将动态分配一个包含所有成员的类,主类将只包含指向该类的指针。然后,您的move构造函数所要做的就是将指针复制到实现类。
如果基元既不比指针大,也不比指针(不知何故)复制成本高,那么动态分配它只是额外的成本。
您可能希望使原件无效,但这不需要指针。
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 为什么调用复制构造函数而不是移动构造函数?
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 具有已删除移动和复制构造函数的类的就地构造
- 移动构造函数和右值引用
- 使用移动调用对等构造函数unique_ptr默认构造函数
- 为什么 std::memmove 中联合的默认非平凡移动构造函数C++?
- 具有专用化的模板类中的可靠条件复制和移动构造函数
- 构造函数采用std::string_view与std::string并移动
- C++:为什么不调用移动构造函数?
- 了解构造函数在移动、复制、赋值语义中的行为
- 没有移动的构造函数移动课程
- 引用绑定和复制构造函数/移动构造函数
- 构造函数移动
- C++ 向量实现 - 移动构造函数 - 移动与前进
- 我真的必须取消移动构造函数/移动结构中的所有成员还是只是指针
- 将类(没有默认构造函数)移动到另一个类的move构造函数中