我曾经假设移动构造函数优先于复制构造函数
,但是在下面的测试中,我发现选择了复制构造函数
您是否知道当foo()
返回向量时,下面代码为什么选择复制构造函数; 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()};
}
结果如下
$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor
I'm normal
I'm move constructor
I'm copy constructor
甚至我在foo中删除了一行,它选择了移动构造函数。。。。
vector<B> foo()
{
vector<B> b;
b.push_back(1);
return b;
}
现在结果如下所示
$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor
其中涉及到两件事:向量重新分配和重新分配时机制的选择。
首先,这里发生重新分配:
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;
}
大多数向量实现在超过current_capacity
时使容量2*current_capacity
,以符合标准要求的摊销恒定复杂度。
现在,编译器只能选择移动构造函数进行重新分配,如果它被标记为noexcept
。 为了使vector使用move构造函数,像这样声明它:
B(B&& other) noexcept
{
//
}
您可以通过预先保留空间来完全删除重新分配:
vector<B> foo()
{
vector<B> b;
b.reserve(2);
b.push_back(1);
b.push_back(2);
return b;
}
或者通过一次性初始化vector:
vector<B> foo()
{
return vector<B>{1, 2};
}