【问题标题】:Should I move a temporary into a variable?我应该将临时变量移入变量吗?
【发布时间】:2015-01-08 19:59:15
【问题描述】:

如果我有一个现有的非平凡变量,并且我想用我将在赋值的同一行声明的新内容重新分配它,我应该使用移动语义吗?

我的问题来自以下场景:

std::vector<string> existing = { ... };

int main(int argc, char *argv[]){
    const char *bunch_of_strings = ... ;
    std::stringstream ss(bunch_of_string);

    existing = std::move(std::vector<std::string>(std::istream_iterator<std::string>(ss), {}));
}

我应该这样做吗,如果我不这样做,编译器是否会进行类似的优化,还是最好不要这样做?

【问题讨论】:

  • 您的分析器向您报告了什么?通常我什至不会考虑上面列出的代码的性能,除非代码被 VTune、Instruments 或 Dtrace 突出显示为性能瓶颈。
  • @AhiyaHiya 我对编译器如何处理它以及它是好还是坏的做法更感兴趣;例如,如果编译器无论如何都会将其转换为移动指令。所以性能不是我主要关心的问题。
  • 在这种特定情况下,您应该使用existing.assign(std::istream_iterator&lt;std::string&gt;(ss), {});,它具有相同的结果,但会重用existing中已经分配的容量。 (见std::vector::assign重载#2)
  • @Casey 这在 user2485710 的答案的 cmets 中进行了讨论。这似乎值得商榷,但我绝对同意你的看法。

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


【解决方案1】:

std::move 在那里是多余的。 move 的目的是在变量不是(或可能不是)时将其视为临时变量(更准确地说,是右值)。如果它已经是一个右值,那么无论如何它肯定会被移动。

【讨论】:

  • 这就是我通常使用move 的方式(当然),但我不确定编译器如何处理这些情况。在阅读了有关复制省略的内容后,我有了一个好主意。
  • @CoffeeandCode 复制省略适用于将临时对象移动到其他一些新初始化的对象时。它不适用于这里,因为向量是被分配的,而不是初始化的。无论如何,编译器总是根据表达式的形式知道什么时候是右值。仅基于使用“构造函数调用”语法句号,就可以保证移动。
  • 是的,我知道。信不信由你,我现在实际上正在尝试编写一个编译器:L 但别担心,在我阅读大量理论和让我的解析器/词法分析器能够从头开始哈哈。
【解决方案2】:

我认为为该向量构造该对象的最合适方法是使用 emplace_back 也就是您只需在适当位置创建该对象,您不复制,您不移动,您只需正确创建该对象是不是应该放在第一位。

emplace_back

【讨论】:

  • 但我的vector 不保证为空。既然我们谈论的是性能,您认为对所有元素使用clear() 然后emplace_back() 将获得最高级别的优化有多贵?
  • 另外,我认为assign() 是最合适的方式。
  • @CoffeeandCode emplace_back 在最后一个元素(如果有的话)之后构造你的对象;你的向量是否为空并不重要。我还认为,在 C++11 及更高版本中清除数组的最有效方法是与空数组交换,你有 std::vector&lt;T&gt; vec; 你清除 vecvec.swap(std::vector&lt;T&gt;{})
  • @CoffeeandCode assign 一点也不灵活,仔细看,它可能只在你有一系列反复重复的元素时才有用,我看不出有什么实际用途assign老实说。
  • 在这种情况下,它所能做的就是制作副本。 stringstream 的底层结构不能保证适合移动到 vector 中,因此您必须将每个单独的元素复制到其中。对于vector::assign(),这似乎是一个很好的案例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 2015-01-20
相关资源
最近更新 更多