【问题标题】:Casting shared_ptr in initializer list在初始化列表中强制转换 shared_ptr
【发布时间】:2020-01-02 03:34:05
【问题描述】:

是否可以在初始化列表中向上转换共享指针对象引用?

我有两个具有匹配派生类的类层次结构。假设我有一个Base 类,它派生到FooBar 类。然后我有一个带有ProxyBase 类的单独层次结构,然后(为了匹配另一个层次结构)有FooProxyBarProxy

ProxyBase 类存储shared_ptr<Base>。创建ProxyFoo 时需要std::shared_ptr<Foo>&,创建ProxyBar 时需要std::shared_ptr<Bar>&

我可以通过两种方式完成这项工作:

  • 不要使用对 std::shared_ptr<*> 对象的引用。
  • 使用std::shared_ptr<Base>& obj 作为ProxyFooProxyBar 构造函数的输入。这需要在构造函数中进行向下转换(我想避免)(因为我想要 FooBar 特定属性),而且它使合同/API 比它应该允许的更多。

但我想知道这是否可以通过引用来完成。

认为我知道问题出在哪里:当我删除引用时它起作用了,我认为这是因为从技术上不允许“强制转换”shared_ptr<X>;它只能通过创建派生/基本类型的新 shared_ptr 对象来“转换”。当使用引用时,人们会尝试将一个 shared_ptr 对象实际转换为另一个不允许的对象。这是正确的吗?

最初我认为这是std::static_pointer_cast 会有所帮助的情况之一,但如果我的假设是正确的,那也无济于事。

独立示例:

#include <memory>

class Base { };

class Foo : public Base
{
private:
  int val_;

public:
  Foo(int val) : val_(val) { }
};

class ProxyBase
{
protected:
  std::shared_ptr<Base> obj_;

  ProxyBase(std::shared_ptr<Base>& obj) : obj_(obj) { }
};

class FooProxy : public ProxyBase
{
public:
  FooProxy(std::shared_ptr<Foo>& fobj) : ProxyBase(fobj) { }
};

int main()
{
  auto f = std::make_shared<Foo>(42);
  auto fp = std::make_shared<FooProxy>(f);
}

所以我的问题归结为:是否可以在不删除引用的情况下在上面的(当前非功能性)代码中做我想做的事情,同时保留 FooBar 特定的构造函数FooProxyBarProxy?

【问题讨论】:

  • 为什么有(非 const)参考?
  • @Jarod42 因为纯粹的无知。 :) 我曾想象过 const 会使 shared_ptr 对象完全不可变(即不能 clone:able(用 Rust 说话)),但 Barry 的回答清楚地表明我在 const 和 shared_ptr 方面存在严重的知识差距。
  • 智能ptr语义遵循ptr语义!

标签: c++ inheritance casting c++17 shared-ptr


【解决方案1】:

shared_ptr&lt;Derived&gt; 可以转换shared_ptr&lt;Base&gt;,但它不是shared_ptr&lt;Base&gt;

换句话说,编译:

std::shared_ptr<Derived> pd;
std::shared_ptr<Base> pb = pd;

但这不是:

std::shared_ptr<Base>& pb = pd;

但这确实如此,因为 const 引用可以绑定到临时对象,这将隐式执行转换:

std::shared_ptr<Base> const& pb = pd;

问题是您在构造函数中使用了非常量左值引用。您应该采用 const 左值引用或仅按值采用它们。

【讨论】:

  • 当然应该是按值然后移动。
猜你喜欢
  • 2012-08-02
  • 2011-10-12
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 2018-06-02
  • 2012-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多