【问题标题】:Sharing objects owned via smart pointer共享通过智能指针拥有的对象
【发布时间】:2018-11-07 17:07:06
【问题描述】:

基本上,我有一个包含要在类之间共享的对象的结构体,如下所示;

struct CoreComponents
{
    std::unique_ptr<a> m_A = std::make_unique<a>();
    std::unique_ptr<b> m_B;
    std::unique_ptr<c> m_C = std::make_unique<c>();
};

在我的主课中,我通过 unique_ptr 拥有它;

class Game
{
    ...
  private:
    std::unique_ptr<CoreComponents> m_Components;
    ...
};

然后我有其他 n 类,我需要从它的函数访问该 m_Components 对象而不创建副本。 (我不会修改那个对象的内容)

我尝试使用 shared_ptrGame 类中保存 m_Components 然后通过它通过值传递给其他类(传递给它们的构造函数)并将其存储,但这种情况会导致内存泄漏。 (我使用 memcheck 来检查泄漏)我发现这是泄漏的原因,但我无法弄清楚究竟是为什么。

Shared_ptr 场景

我需要访问 CoreComponents 对象的类的构造函数;

GameScene::GameScene(std::shared_ptr<CoreComponents> components)
: m_Components(std::move(components))

我试图将它作为 GameScene 类的成员,然后在函数中使用它;

std::shared_ptr<CoreComponents> m_Components;

这就是我从 Game 类内部传递它的方式;

auto gs = std::make_unique<GameScene>(m_Components)

GameScene 类中的一般用法;

m_Components->m_A->draw(*m_OtherObjectInsideGameScene);

那么,使用现代 c++ 创建类似设计的最佳方法是什么? 我试图避免 Singleton 模式,但我必须使用它来实现这一点,还是可以更好地使用智能指针?

PS:当 Game 类被销毁时,CoreComponents 结构体需要从内存中删除。

【问题讨论】:

  • 如果您遇到代码无法正常工作的问题,请发布该代码 - 即使用共享指针的代码。
  • @NeilButterworth 感谢您的反馈。添加了关于共享指针场景的代码。
  • 记住,std::weak_ptr 是一个东西。

标签: c++ oop smart-pointers


【解决方案1】:

您似乎正确地将所有权使用的关注点分开了。您唯一遇到的麻烦是如何将组件转发到系统的其余部分。

我会保留您自己的结构,并为特定用户创建专用结构:

struct CoreComponents {
   unique_ptr<A> a; unique_ptr<B> b; ...
};

struct PartOfTheSystem {
  void use(A& a, B& b);
};

struct Game {
  CoreComponents components;
  PartOfTheSystem user;

  void stuff() {
    user.use(*components.a, *components.b);
  }
};

是的:更多的打字。

而且:非常清晰的逻辑:构造/所有权和使用是独立的关注点,这在设计上是非常清晰的!另请参阅https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-smartptrparam

【讨论】:

  • 引用的使用使这个例子很好。但是,OP 不是说关于存储的吗?
  • 我不明白,并且“......从它的函数中访问那个 m_Components 对象而不创建副本”
  • 我的解释是,所述函数将从存储为成员变量的指针中获取对象。已存储!存储原始指针 => 不好。只是将它们传递给一次性函数是可以接受的。
  • 确实,为了表达长期关系,weak_ptr 在某些情况下可能会更好。但是话又说回来......你失去了对谁拥有和谁不拥有你的物品的控制权。当您接受 R.3 和 R.4 时,您就安全了:只要您需要,其他人就会照看指向的对象。这个意图非常明确,您可以相应地构建您的程序。存储原始指针本身并不坏。
  • @xtofl 而不是将其作为 shared_ptr 或 unique_ptr 我尝试了 const 引用并按原样保持它已清除所有内存泄漏。
【解决方案2】:

如果您有共享对象,最好的方法确实是使用shared_ptr

unique_ptr 是唯一的所有权。

如果您有内存泄漏,是时候调查原因并修复它们了!您的报告建议使用周期性参考。检查意外的 lambda 捕获,在某些地方您可能打算使用 weak_ptr 代替。

为此使用单件就像修理汽车的破轮胎一样,将整件东西放在火上,然后拿一头驴来代替。您的unique_ptr 方法更像是通过拆下轮胎并在轮辋上驾驶来修复汽车的破损轮胎。

【讨论】:

  • 不确定我是否同意。如果我正确理解 gotw91,那么世界的非拥有部分不需要知道任何拥有指针。 (herbsutter.com/2013/06/05/…)
  • @xtofl 一堆垃圾。如果您不需要共享所有权,请将 ref 传递给 shared_ptr。如果需要存储指向资源的非拥有指针,则可以从中获取 weak_ptr。但是剥离所有这些所有权语义只是愚蠢的。
  • @xtofl 永远记住,你读到的一切(包括我说的)只是一个观点。 Herb 可能很突出和受欢迎,但这并不意味着你必须做他所做的事情。 (他还对这种“几乎总是自动”的堕胎负责。)当然欢迎你这样做!
  • 只有当不这样做的性能成本太高以致失去清晰的所有权语义时,我才会使用原始指针 , 并且只在一个非常局部的区域中(所以没有存储,也许有点传递给函数 - 但仍然是 const shared_ptr&!)
  • @LightnessRacesinOrbit 如果我有能力在这里为您的答案和 cmets 提供更多支持...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-04
  • 1970-01-01
  • 2012-10-05
相关资源
最近更新 更多