2012-11-19 48 views
4

我有一个类,它拥有一个指向大量分配内存和大量基元类型成员的指针。我对移动构造函数感兴趣,并认为这是使用它的绝好机会。很显然,指针应该移动过来,但是如果对基元来说是个好主意,那么它就是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}; 
}; 

我的问题是,在堆上分配的开销是否会使移动语义引入的性能增加无效?

+2

“原始材料”是可移动的。 –

+0

抱歉太天真了,但你能详细说明一下吗? –

+0

没有什么需要说明的:你不需要做任何事情来移动基本类型的对象。它只是工作。 –

回答

6

如果有什么,我相信像这样分配每个成员的堆将最终变慢。除了最初的堆分配之外,只在构造上执行,在堆上保存指向很多小的非连续数据成员的指针并不能很好地与CPU缓存策略搭配使用。

一些类移动得非常好,因为它们有大量的堆内存分配(例如std :: string)。在你的情况下,移动每个指针与移动较小的数据类型一样昂贵。我可以看到这个速度更快的唯一方法是如果你将更小的数据成员放在一个堆分配的类/结构体中(可能持有一个unique_pointer),并通过单个指针的移动来移动它们。

这就是说,这很可能是一种过早优化的情况。您可能想要让代码运行起来,并确定为您的类实现更复杂的移动语义确实可以帮助您的代码的性能。

+3

+1用于过早优化。另外,这取决于OP如何使用这个类。如果它的构建比移动更频繁,那么可能需要花费比构建数据结构的堆更多的代价。 –

1

如果原始图像不是比复制指针更大也不会更昂贵,那么动态分配它只是额外的成本。

你可能想无效原件,但不需要指针。

2

移动语义只会在移动对象的速度更快而复制它时更快。在你的例子中,情况并非如此。复制long应该是将指针复制到long的速度相同。通过动态分配每个成员来添加移动语义几乎肯定会减慢速度,而不是加快速度。

什么可能导致更快的移动构造函数使用PIMPL成语。您将动态分配一个包含所有成员的类,主类只包含指向该类的指针。然后,你所有的移动构造函数都必须将指针复制到实现类。