【问题标题】:Copy initialization is effective with move in C++11?复制初始化对 C++11 中的移动有效吗?
【发布时间】:2015-11-18 01:05:24
【问题描述】:

复制初始化是在内存中创建Hello,然后使用复制构造函数初始化s,对吧?

std::string s = std::string("Hello")

在引入移动语义的 C++11 之后,我可以说上面的代码和这种情况一样有效(消除了复制):

std::string s("Hello");

编辑:请不要回答stringstring 只是一个类的例子。 SSO 不是我所要求的。我问一般。

【问题讨论】:

  • 当您使用小于 20 个字符的字符串时(取决于实现),短字符串优化就会启动,并且无论如何都会复制所有内容。
  • @imreal 不需要正好 20 个字符。此外,短字符串优化的细节完全依赖于实现。
  • @MateuszGrzejek,是的,这就是我写“(取决于实现)”的原因
  • 如果您不想了解字符串,请将示例中的类名称更改为用户创建的类。
  • @RobK 已经晚了。 :) 我只是评论说希望答案也能涵盖一般情况。

标签: c++ c++11 copy-constructor move-semantics


【解决方案1】:

简短回答:如果执行复制省略,性能应该相同。否则后者可能会更快。


长答案:

这段代码

std::string s = std::string("Hello")

应该在 C++11+ 代码中调用移动构造函数(它需要一个可访问的构造函数)。无论如何copy elision 在这种情况下是允许的,尽管不是强制的(cfr. [class.copy]/p31

什么时候 满足某些条件时,允许实现省略 复制/移动构造

这些概念在 C++11 之前的版本中已经存在(它们也适用于复制构造函数)。

关于表演问题:

该标准还描述了一些可以消除复制的情况,即使这会改变程序的行为,最常见的是返回值优化。 C++ 标准中描述的另一种广泛实施的优化是将类类型的临时对象复制到相同类型的对象时。 [1]因此,复制初始化在性能上通常等同于直接初始化,但在语义上则不然;复制初始化仍然需要一个可访问的复制构造函数。 [2]

Source - Copy elision

如果没有发生复制省略(例如,它已在 gcc 中通过 -fno-elide-constructors 禁用,或者由于任何原因编译器不会执行它),那么性能可能会相同并且直接初始化应该更快(在这种情况下,std::string SSO 也可能会在移动中产生影响)

【讨论】:

    【解决方案2】:

    当您使用小于 20 个字符的字符串时(取决于实现),短字符串优化就会启动,并且无论如何都会复制所有内容。

    但是要回答您的问题,无论如何,您的任何示例中都没有使用移动语义。在第一种情况下,即使复制构造函数和string(const char*) 构造函数都必须可用,复制省略也会消除复制。

    编辑:

    为了解决您的编辑问题,如果您有一个初始化和一个初始化 + 移动构造函数,那么前者显然总是更快。我提出 SSO 的原因是因为人们认为移动操作总是很便宜(甚至免费),但不一定,有时甚至根本不会发生。

    【讨论】:

    • 你的意思是,如果这些不是std::strings,那么A a("Hello"); 仍然是首选,对吧?
    • @Narek,是的,在发生移动的情况下,尽管在这种特殊情况下,复制省略几乎肯定会发生。
    【解决方案3】:

    其实在C++11之前就是这样,因为copy elision

    请注意,std::string 的移动不一定便宜,因为小字符串可能保存在对象本身中,而不是动态分配的。这被称为small string optimisation

    【讨论】:

      猜你喜欢
      • 2015-07-18
      • 2011-09-10
      • 1970-01-01
      • 1970-01-01
      • 2016-10-08
      • 2014-07-01
      • 2010-11-06
      相关资源
      最近更新 更多