【问题标题】:std::shared_ptr deleted in a getter function with Qt在 Qt 的 getter 函数中删除了 std::shared_ptr
【发布时间】:2017-07-28 09:31:37
【问题描述】:

我在我的 Qt 项目中使用共享指针,但是当我通过共享指针调用 setLayout() 时出现分段错误。

我这样称呼它:

 model->getBody()->setLayout(layoutTemplate.get());

函数getBody()返回一个std::shared_ptr

std::shared_ptr<QWidget> MainTemplate::getBody()
{
   return std::shared_ptr<QWidget>(ui->body);
}

我尝试使用QSharedPointer 而不是std::shared_ptr,但结果相同。

为什么我的指针被删除了?

【问题讨论】:

  • 由于shared_ptr 只存在于该语句的末尾,下次您尝试使用ui-&gt;body 时,它将被删除。
  • 谢谢,所以我不能用getter返回shared_ptr?
  • 你为什么需要shared_ptr
  • 我不知道,这是我主管的要求。
  • 为什么要使用带有父母的 QObjects 的智能指针?你知道父 QObject 在被破坏时会删除它的所有子对象吗?

标签: c++ qt shared-ptr


【解决方案1】:

智能指针表示对象的所有权shared_ptr 特别代表一个由多个实体拥有的对象,并且必须一直存在,直到每个人都完成使用它。每当指向对象的最后一个shared_ptr 被销毁时,它指向的对象也被销毁。 shared_ptr的正确用法是:

std::shared_ptr<T> ptr_a(new T); // Create a T and immediately pass it to shared_ptr
std::shared_ptr<T> ptr_b = std::make_shared<T>(); // Same effect but more efficient

ptr_a = ptr_b; // smart pointer to smart pointer assignment (never existing raw to smart)
ptr_a.reset(new T);            // This is fine.
ptr_a = std::make_shared<T>(); // Same as previous line. Again more efficient

//... eventually ptr_a and ptr_b go out of scope and handle deleting their objects

请注意,在所有重新分配的示例中,ptr_a 检查了引用计数并删除了持有的对象,如果它是最后一个指向它的shared_ptr

通常,您只希望在创建智能指针的确切时刻将原始指针传递给它们。您所做的是将对象的 所有权 传递给临时智能指针。在声明之后,临时的shared_ptr 被销毁了,由于没有复制它,它认为它应该销毁ui-&gt;body。通常你想要做的只是通过非常量引用返回body,或者只是不返回它并为其参数提供setter函数。

QWidget& MainTemplate::getBody()
{
   return ui->body;
}

但是,如果出于某种原因,body 需要能够比其类更长寿(值得怀疑,除非做出了有问题的设计决定),那么您需要将 body 本身设为 shared_ptr 并按值返回。这将创建shared_ptr 的副本,并且您可以保证它们中的最后一个将销毁该对象。但是在 body 构造完成后,你绝不能使用原始指针,也不能手动尝试删除它。

UI {    // whatever class MainTemplate::ui points to
private:
    std::shared_ptr<<QWidget> body;
...
}

MainTemplate {
public:
    std::shared_ptr<QWidget> MainTemplate::getBody()
    {
        return ui->body;
    }
}

同样,如果您的类已经以实用的方式定义,我认为不需要这样做。此外,如果 ui 不属于某个类,您可以将其设为 shared_ptr,并返回它而不是它的主体。然后,让调用者通过返回的shared_ptr&lt;UI&gt; 访问正文。

【讨论】:

    【解决方案2】:

    由于 shared_ptr 只存在到该语句结束时1下次您尝试使用 ui->body 时,它将被删除。

    您可能不想在 getter 中创建新的共享所有权。取而代之的是,所获得的任何东西都应该以 shared_ptr 的形式存在,并且 getter 可以返回(shared_ptr 的)副本。

    或者,在您不转移所有权的情况下,原始指针(body 可以为 null)或引用(body 不能为 null)更合适。指针/引用没有超过被指向/引用的对象的常见警告仍然适用。

    1. 并且没有复制它

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-08
      • 1970-01-01
      • 2016-01-03
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 1970-01-01
      • 2015-04-29
      相关资源
      最近更新 更多