13

我正在使用 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;
}
4

2 回答 2

15

push_back()函数按值获取其参数。因此,尝试复制构造 的参数push_back()(如果您传递的是左值),或者移动构造它(如果您传递的是右值)。

在这种情况下,o是一个左值——因为命名对象是左值——并且右值引用不能绑定到左值。因此,编译器无法调用您的移动构造函数。

为了让你的对象移动,你必须写:

s.push_back(std::move(o));
//          ^^^^^^^^^

在这种情况下让我感到惊讶的是,似乎 VC11MyObject隐式生成了一个复制构造函数,而没有将其定义为已删除(从您发布的错误来看)。这不应该是这种情况,因为您的类声明了一个移动构造函数。实际上,根据 C++11 标准的第 12.8/7 段:

如果类定义没有显式声明复制构造函数,则隐式声明。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认(8.4)

我必须得出结论,虽然你得到的错误是正确的——因为你没有将右值传递给push_back()——VC11 在这里并不完全兼容。

于 2013-04-15T08:24:22.013 回答
4

MyObject o;定义o为一个对象。这意味着它是一个左值。然后,这样做会调用(它别无选择)s.push_back(o);的左值重载,它会尝试创建一个副本。push_back()

由于您的类是不可复制的,因此您必须将对象移动到向量中:

for (int i = 0; i < 5; ++i)
{
    MyObject o;
    s.push_back(std::move(o));
}
于 2013-04-15T08:24:50.833 回答