使用unique_ptr移动语义 [英] Move Semantics with unique_ptr

查看:73
本文介绍了使用unique_ptr移动语义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Visual Studio 2012 Update 2,并且在尝试理解为什么std :: vector试图使用unique_ptr的副本构造函数时遇到麻烦.我看过类似的问题,并且大多数都与没有显式的移动构造函数和/或运算符有关.

如果将成员变量更改为字符串,则可以验证是否调用了move构造函数;但是,尝试使用unique_ptr会导致编译错误:

错误C2248:'std :: unique_ptr< _Ty> :: unique_ptr':无法访问在类'std :: unique_ptr< _Ty>''中声明的私有成员.

我希望有人可以指出我所缺少的内容,谢谢!

  #include< vector>#include< string>#include< memory>MyObject类{上市:MyObject():ptr(std :: unique_ptr< int>(新int)){}MyObject(MyObject&& other):ptr(std :: move(other.ptr)){}MyObject&运算符=(MyObject&& other){ptr = std :: move(other.ptr);返回* this;}私人的:std :: unique_ptr< int>ptr;};int main(int argc,char * argv []){std :: vector< MyObject>s;对于(int i = 0; i< 5; ++ i){MyObject o;s.push_back(o);}返回0;} 

解决方案

push_back()函数按值接受参数.因此,试图复制构造 push_back()的参数(如果您传递左值),或者尝试移动构造它(如果您传递右值).

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

要移动对象 ,您必须编写:

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

在这种情况下令我感到惊讶的是,似乎VC11隐式为 MyObject 生成了一个复制构造函数,而没有将其定义为 deleted (根据您发布的错误来判断).情况并非如此,因为您的类声明了move构造函数.实际上,根据C ++ 11标准的第12.8/7段:

如果类定义未显式声明一个副本构造函数,则隐式声明一个副本构造函数.如果上课定义声明了移动构造函数或移动赋值运算符,即隐式声明的副本构造函数定义为已删除;否则,将其定义为默认值(8.4)

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

I am using Visual Studio 2012 Update 2 and am having trouble trying to understand why std::vector is trying to use the copy constructor of unique_ptr. I have looked at similar issues and most are related to not having an explicit move constructor and/or operator.

If I change the member variable to a string, I can verify that the move constructor is called; however, trying to use the unique_ptr results in the compilation error:

error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'.

I'm hoping someone can point me to what I am missing, thanks!

#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;
}

解决方案

The push_back() function takes its argument by value. Therefore, an attempt is made to either copy-construct the argument of push_back() (if you are passing an lvalue), or to move-construct it (if you are passing an rvalue).

In this case, o is an lvalue - because named objects are lvalues - and rvalue references cannot bind to lvalues. Therefore, the compiler cannot invoke your move constructor.

In order to have your object moved, you have to write:

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

What surprises me in this case is that it seems VC11 generated a copy-constructor for MyObject implicitly without defining it as deleted (judging from the error you posted). This should not be the case, since your class declares a move constructor. Per Paragraph 12.8/7 of the C++11 Standard, in fact:

If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4)

I must conclude that while the error you are getting is correct - because you are not passing an rvalue to push_back() - VC11 is not fully compliant here.

这篇关于使用unique_ptr移动语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆