【问题标题】:Avoiding copy constructor during populating member vector在填充成员向量期间避免复制构造函数
【发布时间】:2018-03-09 04:53:09
【问题描述】:

我有一堂课A:

class A {
  int value1;
  int value2;
  std::string text;

public:
  A(int value1, int value2, std::string text) 
   : value1(value1), value2(value2), text(text) { }
};

还有一些“容器”类B

class B {
  std::vector<A> objects;
  ...

public:
  ...
  void addObject(A a) {
    objects.push_back(a);
  }
};

和代码:

B b;
A a(2, 5, "test");
b.addObject(a);
//I no longer need a from now on

我的问题是,如何优化B::addObject(A a) 以避免任何复制。我想要实现的是通过B的方法将A类型的新对象添加到B.objects

【问题讨论】:

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


【解决方案1】:

这个问题有很多答案。您可以将B 函数更改为move(),并将move() 更改为该函数:

void addObject(A a) { objects.push_back(std::move(a)); }

b.addObject(std::move(a)); // two moves

您可以添加 addObject 的重载,这些重载采用 const 左值引用和右值引用

void addObject(A const& a) { objects.push_back(a); }
void addObject(A&& a) { objects.push_back(std::move(a)); }

b.addObject(std::move(a)); // one move

您可以为 addObject 添加一个函数模板,用于放置:

template <class... Args>
void addObject(Args&&... args) { objects.emplace_back(std::forward<Args>(args)...); }

b.addObject(2, 5, "test"); // zero moves

不管怎样,这里有一个完全不必要的副本:

A(int value1, int value2, std::string text) 
: value1(value1), value2(value2), text(text) { }

你想要的:

A(int value1, int value2, std::string text) 
: value1(value1), value2(value2), text(std::move(text)) { }

【讨论】:

  • 谢谢 :) 一个问题:您的旁注中的text(std::move(text)) 在所有情况下都完全安全吗?另外,这不是编译器会自动执行的任何一种方式(由于优化而移动而不是复制到那里)吗?
  • @PolGraphic 是的 - 构造函数拥有text,因此可以安全地离开。不,它不会。
  • 感谢您的进一步解释。这有点绕主题,但第二个解决方案中的A a(2,5,"test"); b.addObject(std::move(a)); 在性能方面与b.addObject(A{2,5,"test"}); 有什么不同(第二个解决方案创建A 而不是真的移动它)?
  • @PolGraphic 在第二种情况下,被移动的A 将在addObject() 内销毁,但在第一种情况下在a 范围的末尾。但是,基本一样。
【解决方案2】:

您可以更改addObject的参数类型并使用emplace_back,以避免构造一个以后不会使用的A对象并将其复制到vector中。例如

void addObject(int value1, int value2, std::string text) {
  objects.emplace_back(value1, value2, text);
}

B b;
b.addObject(2, 5, "test"); // construct the element directly into the vector without constructing A

【讨论】:

  • 这很好,但对我来说有一个小问题。现在我不涉及A 头文件中任何地方的A 构造函数参数。对于您的解决方案,它需要在B 头文件中提供更多信息(我认为与AB 更相关)。这更多的是外观问题。
  • @PolGraphic 我没明白你的意思,你的意思是在B.h 中添加#include "A.h"?不,应该和push_back一样,如果B.cpp中定义了成员函数,则不需要。
  • 不,我的意思是在B.h 内部,我必须知道并记住A 构造函数参数的顺序。如果它发生变化,我还必须修改B.h
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多