在什么情况下会为构造函数参数调用move构造函数?

时间:2019-04-12 22:40:55

标签: c++11 optimization constructor move-constructor

我试图了解何时调用构造函数参数的move构造函数。

我将使用下面一个实际项目中的一些示例和方案来更好地说明我的问题。

为什么我看到这些情况的结果会有些帮助!

//The following code is common to all examples
//This code is the place the object creation begins
std::unique_ptr<AI::Pathfinding::cDirectedWeightedGraph> graph = std::make_unique<AI::Pathfinding::cDirectedWeightedGraph>(std::move(connections));

x ---------------------------------------------- -------------- x

方案1:

//Here is the actual constructor for the class
cDirectedWeightedGraph(std::vector<cConnection> i_connections) : m_connections(i_connections) {}

结果: 调用std :: vector类的move构造函数。

x ---------------------------------------------- -------------- x

方案2:

//Here is the actual constructor for the class
cDirectedWeightedGraph(std::vector<cConnection>&& i_connections) : m_connections(i_connections) {}

结果: 不会调用std :: vector类的move构造函数。

x ---------------------------------------------- -------------- x

方案3:

//Here is the actual constructor for the class
cDirectedWeightedGraph(std::vector<cConnection>&& i_connections) : m_connections(std::move(i_connections)) {}

结果: 调用std :: vector类的move构造函数。

x ---------------------------------------------- -------------- x

方案4:

//Here is the actual constructor for the class
cDirectedWeightedGraph(std::vector<cConnection> i_connections) : m_connections(std::move(i_connections)) {}

结果: 调用std :: vector类的move构造函数。

x ---------------------------------------------- -------------- x

观察/后续问题:

  1. 如果将参数声明为右值引用,则似乎无关紧要。

  2. 除了为您的类编写移动构造函数或移动赋值运算符外,您是否还需要在构造函数中使用右值引用?

  3. 我假设在构造函数被调用的位置,没有传递右值引用就无法调用move构造函数的方法(这似乎是一种不好的做法,我只是很好奇)。我正在使用std :: move()生成右值引用。

1 个答案:

答案 0 :(得分:0)

我们知道,如果我们调用std::move,则将调用move构造函数,因此期望3和4。

对于1,我首先检查您的编译器设置,debug将不会生成move构造函数。如果那里有一个使用i_connections的语句,则不会看到move构造函数。 clang-tidy甚至有一条规则可以检测到这些情况,并建议将1替换为4。

对于方案2,编译器决定不生成优化的代码。可能有一种启发式方法,与情况1有所不同。即使参数为&&,编译器也不必优化代码,因为它是命名的,因此需要调用移至std::move,以便在所有情况下都可以移动。

因此,对于方案1和2,取决于编译器和标志。

最后,我建议尽可能使用4,因为编译器可以根据需要优化移动,并且接口也可以与副本兼容。