问题
I used to assume that a class' move constructors would be given priority over its copy constructors, but in the code below it seems that the copy constructor is chosen even though the object should be movable.
Do you have any idea why below codes choose copy constructor when foo()
returns vector<B> B
?
#include <iostream>
#include <vector>
using namespace std;
class B {
public:
int var_;
B(int var) : var_(var)
{
cout << "I'm normal" << endl;
}
B(const B& other)
{
cout << "I'm copy constructor" << endl;
}
B(B&& other)
{
cout << "I'm move constructor" << endl;
}
};
vector<B> foo()
{
vector<B> b;
b.push_back(1);
b.push_back(2);
return b;
}
int main()
{
vector<B> b {foo()};
}
The result is as shown below.
$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor
I'm normal
I'm move constructor
I'm copy constructor
Curiously, if I remove one line in foo()
, the move constructor is chosen instead:
vector<B> foo()
{
vector<B> b;
b.push_back(1);
return b;
}
Now the result is like below:
$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor
回答1:
There are two things involved: vector reallocation and selection of mechanism when reallocating.
First, reallocation occurs here:
vector<B> foo()
{
vector<B> b;
b.push_back(1);
std::cout << "Vector capacity: " << b.capacity() << " Vector size: " << b.size() << "\n";
b.push_back(2); //capacity() == size(), reallocation is needed
return b;
}
Most vector implementations make capacity 2*current_capacity
when current_capacity
would be exceeded, to conform to amortized-constant complexity required by standard.
Now, compiler can only choose move constructor for reallocation if it is marked as noexcept
. In order to make vector use move constructor, declare it like this:
B(B&& other) noexcept
{
//
}
You can remove the reallocation altogether by reserving space upfront:
vector<B> foo()
{
vector<B> b;
b.reserve(2);
b.push_back(1);
b.push_back(2);
return b;
}
Or by initializing vector in one go:
vector<B> foo()
{
return vector<B>{1, 2};
}
来源:https://stackoverflow.com/questions/62894254/copy-constructor-chosen-over-move-constructor-when-returning-non-static-local-ob