Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将唯一的_ptr参数传递给构造函数或函数?_C++_Arguments_C++11_Unique Ptr - Fatal编程技术网

C++ 如何将唯一的_ptr参数传递给构造函数或函数?

C++ 如何将唯一的_ptr参数传递给构造函数或函数?,c++,arguments,c++11,unique-ptr,C++,Arguments,C++11,Unique Ptr,我不熟悉C++11中的移动语义,我不太知道如何处理构造函数或函数中的unique\u ptr参数。考虑这个类本身: #包括 阶级基础 { 公众: typedef unique_ptr UPtr; Base(){} Base(Base::uptrn):下一个(std::move(n)){} 虚拟~Base(){} void setNext(基::UPtr n) { next=std::move(n); } 受保护的: Base::UPtr next; }; 这就是我应该如何编写带有唯一\u pt

我不熟悉C++11中的移动语义,我不太知道如何处理构造函数或函数中的
unique\u ptr
参数。考虑这个类本身:

#包括
阶级基础
{
公众:
typedef unique_ptr UPtr;
Base(){}
Base(Base::uptrn):下一个(std::move(n)){}
虚拟~Base(){}
void setNext(基::UPtr n)
{
next=std::move(n);
}
受保护的:
Base::UPtr next;
};
这就是我应该如何编写带有
唯一\u ptr
参数的函数的方法吗

我是否需要在调用代码中使用
std::move

Base::uptrb1;
Base::UPtr b2(新Base());
b1->setNext(b2)//我应该写b1->setNext(std::move(b2));相反

是的,如果您在构造函数中按值获取
唯一\u ptr
,则必须这样做。明确是件好事。由于
unique\u ptr
是不可复制的(私有副本),因此您编写的内容应该会导致编译器错误

Base(Base::UPtr n):next(std::move(n)) {}
应该比现在好多了

Base(Base::UPtr&& n):next(std::forward<Base::UPtr>(n)) {}
应该是

void setNext(Base::UPtr&& n)
身体一样


而且。。。什么是
handle()

编辑:这个答案是错误的,尽管严格来说,代码是有效的。我之所以把它留在这里,是因为下面的讨论太有用了。另一个答案是我上次编辑时给出的最佳答案:

::std::move
的基本思想是,向您传递
唯一\u ptr
的人应该使用它来表达他们知道他们传递的
唯一\u ptr
将失去所有权的知识

这意味着您应该在方法中使用对
unique\u ptr
的右值引用,而不是
unique\u ptr
本身。这无论如何都不会起作用,因为传入一个普通的旧
unique\u ptr
需要制作一个副本,这在
unique\u ptr
的界面中是明确禁止的。有趣的是,使用命名的右值引用会将其再次转换为左值,因此您还需要在方法内部使用
::std::move

这意味着您的两种方法应如下所示:

Base(Base::UPtr &&n) : next(::std::move(n)) {} // Spaces for readability

void setNext(Base::UPtr &&n) { next = ::std::move(n); }
Base newBase(std::unique_ptr<Base>(new Base)); //Illegal in this case.
然后使用这些方法的人会这样做:

Base::UPtr objptr{ new Base; }
Base::UPtr objptr2{ new Base; }
Base fred(::std::move(objptr)); // objptr now loses ownership
fred.setNext(::std::move(objptr2)); // objptr2 now loses ownership

如您所见,
::std::move
表示指针将在最相关和最有用的位置失去所有权。如果这种情况发生在不可见的情况下,那么使用您的类的人会因为没有明显的原因而突然失去所有权,这将非常令人困惑。

以下是将唯一指针作为参数的可能方法,以及它们的相关含义

(A) 按价值 必须对实际l值(命名变量)调用此函数。不能使用这样的临时名称调用它:

Base(Base::UPtr &&n) : next(::std::move(n)) {} // Spaces for readability

void setNext(Base::UPtr &&n) { next = ::std::move(n); }
Base newBase(std::unique_ptr<Base>(new Base)); //Illegal in this case.
不能保证
nextBase
为空。它可能是空的;可能不会。这实际上取决于
Base::Base(std::unique\u ptr&n)
想要做什么。正因为如此,仅仅从函数签名就不太清楚将要发生什么;您必须阅读实现(或相关文档)

因此,我不建议将其作为接口

(C) 按常量l值引用 这与“非常量l值参考”的情况大致相同。区别在于两件事

  • 您可以通过一个临时的:

    Base newBase(std::unique_ptr<Base>(new Base)); //legal now..
    
    您有一个合理的期望,在此行完成后,
    nextBase
    应该为空。应该把它从这里移走。毕竟,你有一个
    std::move
    坐在那里,告诉你已经发生了移动

    问题是它没有。不能保证它已从中移出。它可能已从中移出,但只有通过查看源代码才能知道。您不能仅从函数签名来判断

    建议
    • (A)按值:如果您想让函数声明对
      唯一\u ptr
      的所有权,请按值获取
    • (C)按常量l值引用:如果您的意思是某个函数在该函数执行期间仅使用
      唯一的\u ptr
      ,请按
      常量&
      使用它。或者,将
      &
      常量&
      传递给指向的实际类型,而不是使用
      唯一\u ptr
    • (D)按r值引用:如果函数可以或不可以声明所有权(取决于内部代码路径),则通过
      &
      获取它。但我强烈建议尽可能不要这样做
    如何操作唯一的\u ptr 无法复制
    唯一\u ptr
    。你只能移动它。正确的方法是使用
    std::move
    标准库函数

    如果您按值获取一个
    唯一的\u ptr
    ,您可以从中自由移动。但是移动实际上并没有发生,因为
    std::move
    。采取以下声明:

    std::unique_ptr<Base> newPtr(std::move(oldPtr));
    
    std::unique_ptr newPtr(std::move(oldPtr));
    
    这实际上是两种说法:

    std::unique_ptr<Base> &&temporary = std::move(oldPtr);
    std::unique_ptr<Base> newPtr(temporary);
    
    std::unique\u ptr&&temporary=std::move(oldPtr);
    std::唯一性(临时性);
    
    (注意:以上代码在技术上并不编译,因为非临时的r值引用实际上不是r值。这里仅用于演示目的)

    temporary
    只是对
    oldPtr
    的一个r值引用。移动发生在
    newPtr
    的构造函数中
    unique\u ptr
    的移动构造函数(将
    &&
    带到自身的构造函数)是实际移动的对象


    如果您有一个
    unique\u ptr
    值,并且希望将其存储在某个位置,则必须使用
    std::move
    来进行存储。

    让我尝试说明将指针传递到内存由
    std::unique\u ptr
    类模板实例管理的对象的不同可行模式;它也适用于t
    Base(std::unique_ptr<Base> const &n);
    
    Base(std::unique_ptr<Base> &&n)
      : next(std::move(n)) {}
    
    Base newBase(std::unique_ptr<Base>(new Base)); //legal now..
    
    Base newBase(std::move(nextBase));
    
    std::unique_ptr<Base> newPtr(std::move(oldPtr));
    
    std::unique_ptr<Base> &&temporary = std::move(oldPtr);
    std::unique_ptr<Base> newPtr(temporary);
    
    struct node;
    typedef std::unique_ptr<node> list;
    struct node { int entry; list next; }
    
    size_t length(const node* p)
    { size_t l=0; for ( ; p!=nullptr; p=p->next.get()) ++l; return l; }
    
    list copy(const node* p)
    { return list( p==nullptr ? nullptr : new node{p->entry,copy(p->next.get())} ); }
    
    void f(std::shared_ptr<X> x) // call by shared cash
    { container.insert(std::move(x)); } // store shared pointer in container
    
    void client()
    { std::shared_ptr<X> p = std::make_shared<X>(args);
      f(p); // lvalue argument; store pointer in container but keep a copy
      f(std::make_shared<X>(args)); // prvalue argument; fresh pointer is just stored away
      f(std::move(p)); // xvalue argument; p is transferred to container and left null
    }
    
    void prepend (int x, list& l) { l = list( new node{ x, std::move(l)} ); }
    
    void remove_first(int x, list& l)
    { list* p = &l;
      while ((*p).get()!=nullptr and (*p)->entry!=x)
        p = &(*p)->next;
      if ((*p).get()!=nullptr)
        (*p).reset((*p)->next.release()); // or equivalent: *p = std::move((*p)->next); 
    }
    
    void append (list& a, list&& b)
    { list* p=&a;
      while ((*p).get()!=nullptr) // find end of list a
        p=&(*p)->next;
      *p = std::move(b); // attach b; the variable b relinquishes ownership here
    }
    
    list reversed (list&& l) noexcept // pilfering reversal of list
    { list p(l.release()); // move list into temporary for traversal
      list result(nullptr);
      while (p.get()!=nullptr)
      { // permute: result --> p->next --> p --> (cycle to result)
        result.swap(p->next);
        result.swap(p);
      }
      return result;
    }