将对象传递到函数中时,相同的规则是否适用于智能指针,就像应用于包含动态内存的其他对象一样?
例如,当我将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);
现在,这与智能指针的逻辑相同吗?我什么时候应该考虑移动语义?关于我应该如何传递智能指针的一些指导方针是我最想要的。
智能指针具有指针语义,而不是值语义(好吧,不是你的意思)。把shared_ptr<T>
想象成一个T*
;这样对待它(好吧,除了引用计数和自动删除)。复制智能指针不会复制它指向的对象,就像复制T*
不会复制它指向的T
一样。
您根本无法复制unique_ptr
。该类的全部意义在于它不能被复制;如果可以,那么它就不会是指向对象的唯一(即:单数)指针。您必须通过某种形式的引用或移动它来传递它。
智能指针都是关于它们所指向内容的所有权。谁拥有此内存,谁将负责删除它。unique_ptr
代表唯一的所有权:恰好有一段代码拥有此内存。您可以转移所有权(通过move
),但这样做会失去内存的所有权。shared_ptr
代表共享所有权。
在所有情况下,在参数列表中使用智能指针都表示转移所有权。因此,如果一个函数采用智能指针,那么它将声明该对象的所有权。如果一个函数不应该获得所有权,那么它根本不应该采用智能指针;使用引用 (T&
),或者如果您需要可空性,请使用指针,但从不存储它。
如果你通过某人一个unique_ptr
,你就给了他们所有权。这意味着,由于唯一所有权的性质,您正在失去对内存的所有权。因此,除了价值之外,几乎没有理由通过任何东西传递unique_ptr
。
同样,如果要共享某个对象的所有权,则传入shared_ptr
.您是通过参考还是按价值来做到这一点取决于您。由于您共享所有权,因此无论如何它都会复制(大概),因此您不妨按价值获取它。该函数可以使用std::move
将其移动到类成员等中。
如果函数不打算修改或复制指针,只需使用哑指针即可。智能指针用于控制对象的生存期,但该函数不会更改生存期,因此它不需要智能指针,并且使用哑指针可以在调用方使用的类型方面提供一些灵活性。
void function(std::string * ptr);
function(my_unique_ptr.get());
function(my_shared_ptr.get());
function(my_dumb_ptr);
unique_ptr
不能在不使原件失效的情况下复制,因此如果必须传递它,则必须传递引用。
要更深入地了解比我聪明得多的人的这个建议,请参阅 Herb Sutter 的 GotW #91 解决方案:智能指针参数。 他超越了这个建议,并建议如果指针不能为 null,则应通过引用而不是指针传递。 这需要在调用站点取消引用指针。
void function(std::string & val);
assert(my_unique_ptr != nullptr && my_shared_ptr != nullptr && my_dumb_ptr != nullptr);
function(*my_unique_ptr);
function(*my_shared_ptr);
function(*my_dumb_ptr);
智能指针是引用另一个对象并管理其生存期的对象。
传递智能指针需要遵守智能 poitner 支持的语义:
- 以
const smartptr<T>&
传递始终有效(您无法更改指针,但可以更改其指向的状态)。 - 传递
smartptr<T>&
始终有效(您也可以更改指针)。 - 仅当smartptr可复制时,作为
smartptr<T>
传递(通过副本)才有效。它适用于std::shared_ptr
,但不适用于std::unique_ptr
,除非你在调用时"移动"它,就像在func(atd::move(myptr))
中一样,从而使myptr
无效,将指针移动到传递的参数。(请注意,如果移动是临时的,则移动是隐式的myptr
)。 - 按
smartptr<T>&&
传递(通过移动)通过强制您显式使用std::move
来强制要在调用时移动指针(但需要"移动"才能对特定指针有意义)。
- 我知道问这个问题的人在C++方面比我知识渊博,这个问题有一些完美的答案,但我相信这个问题最好以一种不会吓到人们的方式回答C++,尽管它可能有点复杂,这是我的尝试:
考虑到C++中只有一种类型的智能指针,它是shared_ptr的,所以我们有以下选项将其传递给函数:
1 - 按值:void f(std::shared_ptr<Object>);
2 -参考:void f(std::shared_ptr<Object>&);
最大的区别是,第一个借给你所有权,第二个让你操纵所有权。
进一步阅读和详细信息可以在这个链接上,这之前对我有帮助。