将对象传递给函数时,相同的规则是否适用于智能指针以及包含动态内存的其他对象?
当我将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);
现在这与智能指针的逻辑相同吗?什么时候应该考虑移动语义?关于如何通过智能指针的一些指导是我最想要的。
答案 0 :(得分:19)
智能指针具有指针语义,而不是值语义(嗯,不是你的意思)。将shared_ptr<T>
视为T*
;这样对待(好吧,除了参考计数和自动删除)。复制智能指针不会复制它指向的对象,就像复制T*
不会复制它指向的T
一样。
您根本无法复制unique_ptr
。该类的重点是不能被复制;如果它可以,那么它将不是指向对象的唯一(即:单数)指针。您必须通过某种形式的引用或移动来传递它。
智能指针完全是关于他们所指向的所有权。谁拥有这个记忆,谁将负责删除它。 unique_ptr
表示唯一所有权:正好一段代码拥有此内存。您可以转移所有权(通过move
),但这样做会导致失去内存的所有权。 shared_ptr
代表共享所有权。
在所有情况下,在参数列表中使用智能指针代表转移所有权。因此,如果函数采用智能指针,那么它将声明该对象的所有权。如果一个函数不应该取得所有权,那么它根本不应该采用智能指针;使用引用(T&
)或者如果你需要可空性,那么指针却永远不会存储它。
如果您传递某人unique_ptr
,则给予他们所有权。这意味着,根据独特所有权的性质,您失去内存的所有权。因此,几乎没有理由通过除{value}之外的任何东西传递unique_ptr
。
同样,如果您想共享某个对象的所有权,则传入shared_ptr
。无论您是通过引用还是按价值来做,都取决于您。既然你正在分享所有权,那么无论如何它都会制作一份副本(大概),所以你不妨按价值来看待它。该函数可以使用std::move
将其移动到类成员等中。
答案 1 :(得分:4)
智能指针是一个对象,它引用另一个对象来管理它的生命周期。
传递智能指针需要尊重智能助手支持的语义:
const smartptr<T>&
始终有效(并且您无法更改指针,但可以更改其指向的状态)。smartptr<T>&
始终有效(并且您也可以更改指针)。smartptr<T>
(通过副本)仅在 smartptr 可复制时才有效。它适用于std::shared_ptr
,但不适用于std::unique_ptr
,除非您在调用时“移动”它,就像在func(atd::move(myptr))
中一样,从而使myptr
无效,将指针移动到传递的参数。 (请注意,如果myptr
是临时的,则隐式移动。)smartptr<T>&&
(通过移动)强制指针在调用时被移动,强制您明确使用std::move
(但需要“移动”以使特定指针有意义)。 / LI>
答案 2 :(得分:4)
如果该函数不会修改或复制指针,则只需使用哑指针。智能指针用于控制对象的生命周期,但该函数不会改变生命周期,因此它不需要智能指针,并且使用哑指针可以为调用者使用的类型提供一些灵活性。
void function(std::string * ptr);
function(my_unique_ptr.get());
function(my_shared_ptr.get());
function(my_dumb_ptr);
unique_ptr
无法复制,因此如果必须通过,则必须传递参考。