可以将右值移动到 shared_ptr 中吗
Posted
技术标签:
【中文标题】可以将右值移动到 shared_ptr 中吗【英文标题】:Can an rvalue be moved into a shared_ptr 【发布时间】:2016-02-24 13:23:09 【问题描述】:是否可以将rvalue
“移动”到shared_ptr
。到目前为止我尝试过的所有方法都会产生副本。
我想要的使用模式是:
class Element
public:
Element(const string &);
Element(const Element &) = delete; //delete copy constructor
// ...
;
class MyCollectionOfElements
public:
void add(Element &&); // add by rvalue
// ...
protected:
vector<shared_ptr<Element>> elements;
;
MyCollectionOfElements elements;
elements.add(Element("something"));
我想要这种模式是有原因的,并且了解有一些自然有效的替代模式(例如,将新的 Element
作为指针而不是 rvalue
传递)。
我目前的怀疑是传入的rvalue
在堆栈上,而我需要将它放在堆上以将其存储在shared_ptr
中,因此副本是不可避免的。
【问题讨论】:
C++ 中没有“堆栈”或“堆”(std::stack
和 std::make_heap
除外)。
我认为他指的是程序的stack 和heap,它们在C++ 中绝对存在
@Conduit:C++ 需要引用。
它们是编程语言的主要内容。当您分配变量、将它们传递给函数或使用内存进行任何操作时,数据将存储在这两种结构之一中。
I'll just leave this here 并在路上。
【参考方案1】:
是的:
void add(Element && e)
elements.push_back(std::make_shared<Element>(std::move(e)));
你还必须确保你的类实际上有一个移动构造函数:
class Element
public:
Element(Element &&) = default;
// ...
;
通过声明一个复制构造函数,你禁止了一个移动构造函数的隐式声明,所以你需要显式声明它。
【讨论】:
谢谢你,Kerrek。这在 Visual Studio 中不像我预期的那样工作。除非我不删除复制构造函数,否则这不会编译。当它返回复制构造函数时,我可以看到在 make_sharedthis
仍然无效。this
指针应该保持不变——您应该在问题中澄清这一点。可能无法避免更改 this
指针(但这是移动与复制之外的另一个问题)。
@ElliotWoods:这不是“移动”通常的意思。你永远不能“移动”一个实际的变量。 “移动”总是指移动变量的值。提供的代码是您应该想要的。
@KerrekSB - 谢谢。你能想象为什么我可能需要在 Visual Studio 中允许复制构造函数才能让你的方法工作吗?
@ElliotWoods:我不太明白你的问题。您能否将问题简化为尽可能小的形式并将其作为单独的问题发布?【参考方案2】:
猜你误解了运动语义的概念。您必须将指针传递给智能指针,并且指针可以具有任何类型 - 左值/右值
void f(A *&&p)
接受右值引用指向指向A的指针的函数;但是 p 仍然是左值,它具有对指针的 r 值引用类型, 所以你必须“cast”(std::move - 什么都不做,只是将 l-value 转换为 r-value) std::shared_ptr(std::move(p));
A *g() return new A;
A *a;
f(a);//error
f(g());//works fine
f(new A());//also fine
【讨论】:
谢谢 jonezq,但问题是如何(如果可能)从Element &&
(不是Element * &&
)创建shared_ptr<Element>
,而不导致Element
的副本
您可以获取右值对象的地址并将其传递给 shared_ptr,然后您就可以离开函数/方法范围 - 对象被销毁,并且当 shared_ptr 递减 ref 计数器为零时也会调用析构函数被破坏的对象(意外行为)。以上是关于可以将右值移动到 shared_ptr 中吗的主要内容,如果未能解决你的问题,请参考以下文章