我有一个类,它包含一个指向大块已分配内存和许多基本类型成员的指针。我正在考虑移动构造函数,并认为这是一个使用它的绝佳机会。显然,如果对于基元是一个好主意,指针应该移动但是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};
};
我的问题是,在堆上分配的开销是否会使移动语义引入的性能增加无效?
答案 0 :(得分:6)
如果有的话,我相信像这样分配每个成员的堆最终会变慢。在初始堆分配之上,仅在构造上执行,在堆上保存指向许多小的,非连续数据成员的指针不能很好地与CPU缓存策略一起使用。
有些类移动得很好,因为它们具有大量堆分配的内存(例如std :: string)。在您的情况下,移动每个指针将与移动较小的数据类型一样昂贵。我可以看到这个更快的唯一方法是将较小的数据成员包装在堆分配的类/结构中(可能包含一个unique_pointer)。并通过单个指针的移动移动所有这些。
尽管如此,这很可能是一个过早优化的情况。您可能希望让代码工作原理并确定为您的类实现更复杂的移动语义真的可以真正帮助您的代码的性能。
答案 1 :(得分:2)
移动对象比移动对象更快,移动语义更快。在你的例子中,这不是真的。复制long应该是将指针复制到long的速度相同。通过动态分配每个成员来添加移动语义几乎肯定会减慢速度,而不是加快速度。
可能导致更快移动构造函数的原因是使用PIMPL习惯用法。您将动态分配一个包含所有成员的类,主类只包含指向该类的指针。然后,你的所有移动构造函数都必须将指针复制到实现类。
答案 2 :(得分:1)
如果原语既不比指针更大也不会(某种程度上)比指针更昂贵,那么动态分配它只是额外的成本。
您可能希望使原件无效,但这不需要指针。