简体   繁体   English

将std :: unique_ptr推回到std :: vector时,编译器不会失败

[英]Compiler doesn't fail when pushing back a std::unique_ptr into a std::vector

An unique_ptr cannot be pushed back into a std::vector since it is non-copyable, unless std::move is used. unique_ptr不能被推回到std::vector因为它是不可复制的,除非使用了std::move However, let F be a function that returns a unique_ptr , then the operation std::vector::push_back(F()) is allowed. 但是,让F是一个返回unique_ptr的函数,然后允许操作std::vector::push_back(F()) There is an example below: 下面有一个例子:

#include <iostream>
#include <vector>
#include <memory>

class A {
  public:
    int f() { return _f + 10; }

  private:
    int _f = 20;
};

std::unique_ptr<A> create() { return std::unique_ptr<A>(new A); }


int main() {
  std::unique_ptr<A> p1(new A());

  std::vector< std::unique_ptr<A> > v;

  v.push_back(p1); // (1) This fails, should use std::move

  v.push_back(create()); // (2) This doesn't fail, should use std::move?

  return 0;
}

(2) is allowed, but (1) is not. (2)是允许的,但(1)不是。 Is this because the returned value is moved somehow implicitly? 这是因为返回的值以某种方式隐式移动了吗?

In (2) , is it actually necessary to use std::move ? (2) ,实际上是否需要使用std::move

std::move(X) essentially means "here, treat X as if it was a temporary object". std::move(X)实质上意味着“在这里,将X看作是一个临时对象”。

create() returns a temporary std::unique_ptr<A> to begin with, so move is unnecessary. create()返回一个临时的std::unique_ptr<A> ,所以不需要move


If you want to know more, look into the value categories . 如果您想了解更多信息,请查看值类别 Your compiler uses value categories to determine if an expression refers to a temporary object ("rvalue") or not ("lvalue"). 您的编译器使用值类别来确定表达式是否引用临时对象(“rvalue”)或不引用(“左值”)。

p1 is an lvalue, and create() is an rvalue. p1是左值, create()是右值。

std::vector::push_back() has an overload that takes an rvalue reference as input: std::vector::push_back()有一个重载,它将rvalue引用作为输入:

void push_back( T&& value );

The return value of create() is an unnamed temporary, ie an rvalue, so it can be passed as-is to push_back() without needing to use std::move() on it. create()的返回值是一个未命名的临时值,即一个rvalue,因此它可以按原样传递给push_back()而不需要在其上使用std::move()

std::move() is needed only when passing a named variable, ie an lvalue, where an rvalue is expected. 只有在传递一个命名变量(即左值std::move()时才需要std::move() ,其中rvalue是预期的。

With C++11 we got move constructors and rvalues semantics. 使用C ++ 11,我们得到了移动构造函数和rvalues语义。

std::move(X) is just a cast to a rvalue which converts X to X&& that is it. std :: move(X)只是对rvalue的强制转换,它将X转换为X &&即它。 Than move ctor takes the job over and move constructors typically "steal" the resources held by the argument. 比移动ctor接管工作并移动构造函数通常“窃取”参数所持有的资源。 unique_ptr have a move ctor. unique_ptr有一个移动ctor。

Function return values are already a rvalue(unless the function returns an lvalue reference as indicated by @HolyBlackCat in comments) which will trigger the move ctor without needing any extra cast. 函数返回值已经是一个右值(除非函数返回一个左值引用,如注释中的@HolyBlackCat所示),它将触发移动ctor而不需要任何额外的强制转换。 And since move ctor is defined for unique_ptr it will compile. 因为move ctor是为unique_ptr定义的,所以它会编译。

Also the reason why v.push_back(p1);failing is: you try to call copy constructor with an lvalue and it fails because unique_ptr does not have a copy ctor. 另外v.push_back(p1);失败的原因是:您尝试使用左值调用复制构造函数并且它失败,因为unique_ptr没有复制ctor。

It is also worth knowing that it would also work due to compiler ability to move objects that are not move explicitly (NRVO) 值得一提的是,由于编译器能够移动未明确移动的对象(NRVO),它也可以工作

#include <iostream>
#include <vector>
#include <memory>

class A {
  public:
    int f() { return _f + 10; }

  private:
    int _f = 20;
};

std::unique_ptr<A> create() {
    std::unique_ptr<A> x (new A);
    return x; 

}


int main() {
  std::unique_ptr<A> p1(new A());

  std::vector< std::unique_ptr<A> > v;

  //v.push_back(p1); // (1) This fails, should use std::move

  v.push_back(create()); // (2) This doesn't fail, should use std::move?

  return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM