【问题标题】:How does std::shared_ptr converts across class hierarchy when passing by reference?通过引用传递时,std::shared_ptr 如何跨类层次结构转换?
【发布时间】:2015-04-18 23:09:53
【问题描述】:

查看 20.8.2.2 类模板 shared_ptr [util.smartptr.shared] 我意识到 std::shared_ptr 具有模板复制构造函数和赋值运算符,允许从shared_ptr<Derived>shared_ptr<Base> 当且仅当 Derived* 可转换为 Base*。这些转换(在我的理解中)仅通过模板化的复制构造函数和赋值运算符完成。但是,似乎我也可以将 shared_ptr<Derived> 传递给采用 shared_ptr<Base>& 的函数(即通过引用传递)。似乎应该有一个隐式转换运算符,但根据标准没有。

下面的代码阐明了我的意思:

#include <iostream>
#include <memory>

struct Base {};
struct Derived: Base {};

void f(const std::shared_ptr<Base>& ) {}

int main()
{
    std::shared_ptr<Derived> spDerived(new Derived);

    // conversion below is OK, via template copy ctor
    std::shared_ptr<Base> spBase(spDerived); 
    // also OK, via template copy assignment operator
    spBase = spDerived; 

    // why is this OK? Cannot see any conversion operators in
    // 20.8.2.2 Class template shared_ptr [util.smartptr.shared]
    f(spDerived); 
}

我的问题:在这种情况下,谁在调用f(spDerived) 中执行从shared_ptr&lt;Derived&gt;shared_ptr&lt;Base&gt; 的转换? (对于编译器shared_ptr&lt;Derived&gt;shared_ptr&lt;Base&gt; 没有任何关系,即使DerivedBase 的子级)

【问题讨论】:

  • 一个临时的std::shared_ptr&lt;Base&gt; 是通过转换构造函数创建的,并绑定到引用。也就是说,调用相当于f(std::shared_ptr&lt;Base&gt;(spDerived))
  • 我说的是转换构造函数,而不是复制构造函数(构造函数模板永远不是复制构造函数;/end pedantic 模式)。无论如何,你怎么知道没有构造函数被调用?由于您的函数是无操作的,很可能整个调用都被优化掉了。
  • @IgorTandetnik 我想我明白发生了什么,编译器可以执行一次用户定义的转换,并且可以调用模板转换 ctor...然后将 temp 绑定到 const ref。跨度>
  • 您的问题和下面接受的答案都谈到了模板复制构造函数。正如伊戈尔已经解释的那样,没有这样的事情。构造函数模板永远不能是复制/移动构造函数。此处使用的构造函数是编号为 (9) here 的第二个构造函数。您已经了解这里发生了什么,但是删除f 的参数类型中的const 并查看代码如何编译失败(在MSVC 上不会失败)可能会很有趣。

标签: c++ c++11 type-conversion shared-ptr implicit-conversion


【解决方案1】:

通过模板复制 ctor 创建一个临时副本,该副本就是被引用的内容。 ctor 是隐含的,因此在这种情况下可以合法地调用它。从根本上讲,这个电话和f(std::string); f("hello"); 之间没有区别。完全相同的机制在起作用。这是一个常规的隐式转换。

【讨论】:

  • 我通过 const 引用传递,所以它应该是安全的。我只是不明白为什么要调用复制构造函数。
  • @vsoftco:哦,我一定是脑残了,根本没看到const。复制构造函数被调用是因为它是隐式的,所以编译器可以隐式创建一个临时的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-13
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
相关资源
最近更新 更多