如何将智能指针传递给函数?
Posted
技术标签:
【中文标题】如何将智能指针传递给函数?【英文标题】:How do I pass smart pointers into functions? 【发布时间】:2012-09-13 05:50:49 【问题描述】:将对象传递给函数时,是否适用于智能指针和其他包含动态内存的对象一样的规则?
例如,当我将std::vector<std::string>
传递给函数时,我总是会考虑以下选项:
我要更改矢量对象的状态,但我不希望在函数完成后反映这些更改,AKA 复制。
void function(std::vector<std::string> vec);
我要更改矢量对象的状态,并且我确实希望在函数完成后反映这些更改,AKA 做一个参考。
void function(std::vector<std::string> & vec);
这个对象很大,所以我最好传递一个引用,但是告诉编译器不要让我改变它。
void function(std::vector<std::string> const& vec);
现在这与智能指针的逻辑相同吗?我什么时候应该考虑移动语义?一些关于我应该如何传递智能指针的指南是我最想要的。
【问题讨论】:
unique_ptr
不可复制,您必须手动进行复制。 std::unique_ptr<T>(mew T(*otherptr));
除此之外应该和向量一样。
见cpp-next.com/archive/2009/08/want-speed-pass-by-value和***.com/questions/8114276/…
“移动语义是怎么回事?”这是一个完全不同的问题,已经被提出并回答了。
【参考方案1】:
智能指针具有指针语义,而不是值语义(嗯,不是你的意思)。将shared_ptr<T>
视为T*
;像这样对待它(好吧,除了引用计数和自动删除)。复制智能指针不会复制它指向的对象,就像复制T*
不会复制它指向的T
。
您根本无法复制unique_ptr
。这个类的重点是它不能被复制;如果可以,那么它就不是指向对象的 unique(即:单数)指针。您必须通过某种形式的引用或通过移动它来传递它。
智能指针都是关于它们所指对象的所有权。谁拥有此内存,谁将负责删除它。 unique_ptr
代表唯一所有权:只有一段代码拥有该内存。您可以转让所有权(通过move
),但这样做会失去内存的所有权。 shared_ptr
代表共享所有权。
在所有情况下,在参数列表中使用智能指针表示转让所有权。因此,如果一个函数采用智能指针,那么它将声明该对象的所有权。如果一个函数不应该拥有所有权,那么它根本不应该使用智能指针;使用引用 (T&
) 或者如果您需要可空性,则使用指针但永远不要存储它。
如果您将unique_ptr
传递给某人,则表示您授予他们所有权。这意味着,根据唯一所有权的性质,您将失去内存的所有权。因此,除了值之外,几乎没有理由通过任何方式传递unique_ptr
。
同样,如果你想共享某个对象的所有权,你可以传入shared_ptr
。你是通过参考还是通过价值来做这件事取决于你。由于您共享所有权,因此无论如何它都会复制(大概),因此您不妨按价值接受它。该函数可以使用std::move
将其移动到类成员等中。
【讨论】:
所以,只是一个愚蠢的问题:如果您通过值传递unique_ptr
会发生什么?它不是复制它,这违反了它的唯一性吗?或者您的意思是说unique_ptr
只能通过引用传递?
@MihaiTodor:必须是doSomenthing(std::move(x));
;你不能隐式移动左值。
即使函数没有所有权,我也不建议使用哑指针。最好始终使用智能指针。如果所有权不受影响,只需通过const&
传递它们。这将使您的代码更加万无一失,并避免编写类似void f(T*); f(new T());
的内容。
@Rost: +1 避免裸指针。然而,在许多情况下,如何管理对象的生命周期与函数无关。该函数应该只接受一个T&
,如果调用者实际上是一个(智能)指针,则调用者可以取消引用。
@Deduplicator:好的,某些 API 采用可能为空的指针是完全有效的。但坦率地说,它远 比函数毫无疑问需要一个真实对象的情况少见。因此,在可能的情况下更倾向于参考的一般建议最终仍然有效。【参考方案2】:
如果函数不打算修改或复制指针,只需使用哑指针代替。智能指针用于控制对象的生命周期,但该函数不会更改生命周期,因此它不需要智能指针,并且使用哑指针可以为调用者使用的类型提供一些灵活性。
void function(std::string * ptr);
function(my_unique_ptr.get());
function(my_shared_ptr.get());
function(my_dumb_ptr);
unique_ptr
不能被复制,所以如果你必须传递它,你必须传递一个引用。
【讨论】:
-1: factual error: "so if you must pass it you must pass a reference." 你可以进入参数。 @NicolBolas:但是如果被移动了,对象就会被销毁,这样会报错。 @Deduplicator:请参阅我关于如何传递智能指针的帖子。或者更重要的是,你怎么不这样做。 @NicolBolas:也许我今天有点慢,但我没有得到你想要指出的内容。这个答案的重点似乎是,如果该参数仅用于访问指针而不是转移所有权,则要求任何智能指针类型都太麻烦了,而应该使用原始(观察)指针。您的第一条评论说,可以改为进入智能指针参数。这会转移所有权,对我来说似乎是错误的。 @NicolBolas 这是真的,你不能,除非你打算改变指针的所有权。阅读答案的第一句话,了解它所依赖的资格。【参考方案3】:智能指针是一个引用另一个对象并管理其生命周期的对象。
传递智能指针需要尊重智能指针支持的语义:
作为const smartptr<T>&
传递始终有效(您无法更改指针,但可以更改其指向的状态)。
以smartptr<T>&
传递始终有效(您也可以更改指针)。
仅当 smartptr 可复制时,以smartptr<T>
的形式传递(通过复制)才有效。它适用于std::shared_ptr
,但不适用于std::unique_ptr
,除非您在调用时“移动”它,就像在func(atd::move(myptr))
中一样,从而使myptr
无效,将指针移动到传递的参数。 (请注意,如果 myptr
是临时的,则移动是隐含的)。
作为smartptr<T>&&
传递(通过移动)通过强制您显式使用std::move
(但需要“移动”以使特定指针有意义)来强制在调用时移动指针。
【讨论】:
"pssign as smartptrT&&
。在构造对象之前不会发生实际运动。
@NicolBolas:这正是我的概念:通过强制使用 std::move 来“强制移动”,否则函数不会绑定。如果我改写可能会更好......
-1:事实错误:“passign as smartptr考虑到 C++ 中只有一种智能指针,它是 shared_ptr,所以我们有以下选项可以将它传递给函数:
1 - 价值:void f(std::shared_ptr<Object>);
2 - 参考:void f(std::shared_ptr<Object>&);
最大的不同是,第一个借给你所有权和第二个让你操纵所有权。
进一步阅读和详细信息可以在this link 之前帮助过我。
【讨论】:
以上是关于如何将智能指针传递给函数?的主要内容,如果未能解决你的问题,请参考以下文章