我正在使用Visual Studio 2012 Update 2,并且无法理解为什么std :: vector正在尝试使用unique_ptr的复制构造函数。我已经看过类似的问题,大多数都与没有明确的移动构造函数和/或运算符有关。
如果我将成员变量更改为字符串,我可以验证是否调用了移动构造函数;但是,尝试使用unique_ptr会导致编译错误:
error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
。
我希望有人能指出我所缺少的东西,谢谢!
#include <vector>
#include <string>
#include <memory>
class MyObject
{
public:
MyObject() : ptr(std::unique_ptr<int>(new int))
{
}
MyObject(MyObject&& other) : ptr(std::move(other.ptr))
{
}
MyObject& operator=(MyObject&& other)
{
ptr = std::move(other.ptr);
return *this;
}
private:
std::unique_ptr<int> ptr;
};
int main(int argc, char* argv[])
{
std::vector<MyObject> s;
for (int i = 0; i < 5; ++i)
{
MyObject o;
s.push_back(o);
}
return 0;
}
答案 0 :(得分:12)
push_back()
函数按值获取其参数。因此,尝试复制构造push_back()
的参数(如果传递左值),或者移动构造它(如果传递右值)。
在这种情况下,o
是左值 - 因为命名对象是左值 - 并且右值引用无法绑定到左值。因此,编译器无法调用您的移动构造函数。
为了让你的对象移动,你必须写:
s.push_back(std::move(o));
// ^^^^^^^^^
在这种情况下让我感到惊讶的是,似乎VC11隐式地为MyObject
生成了一个复制构造函数,而没有将其定义为 deleted (根据您发布的错误判断)。这不应该是这种情况,因为您的类声明了一个移动构造函数。根据C ++ 11标准的第12.8 / 7段,事实上:
如果类定义没有显式声明复制构造函数,则会隐式声明一个。 如果上课 definition声明一个move构造函数或move赋值运算符,隐式声明的复制构造函数 被定义为已删除;否则,它被定义为默认(8.4)
我必须得出结论,虽然你得到的错误是正确的 - 因为你没有将右值传递给push_back()
- VC11在这里并不完全符合。
答案 1 :(得分:4)
MyObject o;
将o
定义为对象。这意味着它是一个l值。然后执行s.push_back(o);
调用push_back()
的l值重载(它没有其他选择),它会尝试创建副本。
由于您的类是不可复制的,您必须将对象移动到向量中:
for (int i = 0; i < 5; ++i)
{
MyObject o;
s.push_back(std::move(o));
}