在自定义类中移动vs复制性能

时间:2017-07-10 21:22:24

标签: c++ oop c++11 c++14 move-semantics

如果所有类的成员主要是基本类型如int等,那么如果(如果有的话)通过move ctor创建类的实例来提高性能,与copy ctor相比如何。 这些成员是不是像副本一样被复制了?那么什么时候移动提供更好的性能,在处理自定义类时呢?

3 个答案:

答案 0 :(得分:5)

  

如何(如果有的话)通过移动ctor创建类的实例   如果成员说,相比复制ctor,提高性能   class主要是像int这样的基本类型。不仅仅是那些成员   复制像复制ctor?

在所有成员变量都是按值/ POD的情况下,根本不存在任何差异。

  

因此,在处理时,移动何时提供更好的性能   自定义类?

移动构造函数仅在新构造的对象可以“窃取”的情况下提供优势。来自已存在对象的资源。

例如,假设您有一个临时的std::string,其中包含小说“战争与和平”的全部内容。 - 所有1440页。

在经典复制构造函数的情况下,如果要将该临时字符串分配给非临时std::string(例如成员变量或全局变量或其他),程序必须执行以下步骤:

  • 释放目标std::string可能持有的任何先前缓冲区
  • 为目标std::string分配一个长度为(1440 * chars_per_page)字节的新缓冲区
  • 将所有1440页数据从临时std::string缓冲区复制到目标std::string缓冲区
  • 删除临时字符串的缓冲区(当临时字符串超出范围时)

正如您所看到的,这将是低效的,因为我们复制了大量数据,即使我们实际上从未需要第二份数据。因为我们有一个为std::string实现的移动构造函数,但是,C ++ 11程序可以更聪明,只需执行此操作:

  • 释放目标std::string可能持有的任何先前缓冲区
  • 将巨型缓冲区从临时std::string传输到目标std::string(请注意,我们所做的只是将源字符串的指针缓冲区值复制到目标字符串;在特别是我们需要复制甚至阅读任何实际的1440页数据!)
  • 将临时字符串的指向缓冲区的值设置为NULL(因此它不会尝试释放它或稍后使用它)

......就是这样;而不是必须分配第二个大缓冲区,然后复制大量数据,我们只需通过调整几个指针值就可以实现所需的最终状态。这是一个很大的表现胜利,我们可以放弃这样做,因为我们知道临时字符串即将被删除,所以在"偷窃"它持有的内部数据。

我不知道std::string是否算作自定义班级'确切地说,但是只要你有一个动态分配内部状态的类,你就可以在你自己的类中使用相同的技术。

答案 1 :(得分:1)

  

如果所有类的成员主要是基本类型(如int等),那么如何(如果有的话)通过move ctor创建类的实例来提高性能,与copy ctor相比。

它没有。

  

Aren那些刚刚复制的成员就像复制文件一样?

  

那么在处理自定义类时,移动何时提供更好的性能?

当你有"间接"资源,就像指针引用的数据一样,你只需要交换"指针,甚至避免触及他们指向的东西。 (这就像是从你的车上取下一辆大篷车,然后把它重新挂在另一辆车上。)就是这样。

如果一个类只包含必须复制的数据,那么使一个类可以移动是没有好处的。 (这就像试图"将大篷车的内容移动到另一辆大篷车:你别无选择,只能实际进去,拿起所有东西并手工转移。)

答案 2 :(得分:0)

  

如何(如果有的话)通过移动来创建类的实例ctor与复制文件相比提高了性能

你误会了。通常情况下,您不会选择是使用移动控制器还是复制控制器构造对象 - 它在其定义的上下文中是隐含的。所以它不像那里有很多选择。当然,如果没有移动ctor,那么复制构造就是后备。不过,不要把它当作一种选择。

  

如果所述类的成员主要是基本类型,如int等,那些成员只是像复制文件一样被复制?

它们可能根本不会被复制,即编译器可能会完全忽略对象的构造,只使用你传递的对象。但是如果构造真的发生了,那么是,int s只会被复制(假设默认移动ctor)。

  

那么在处理自定义类时,移动何时提供更好的性能?

再一次,你在想错了。移动构造函数用于移动,复制构造函数用于复制。对于某些类,移动构造函数可能更快(例如,如果您可以切换分配的缓冲区等);对某些人来说,不是。

进一步阅读Reasonable presentation on these two kinds of ctors上的Andrzej's C++ blog