【问题标题】:Why does one need a null shared_ptr and how can it be used?为什么需要一个空的 shared_ptr 以及如何使用它?
【发布时间】:2011-07-28 21:45:38
【问题描述】:

在 Scott Meyers 的 Effective C++ 的第 18 条使接口易于正确使用和难以错误使用中,他提到了 null shared_ptr:

std::tr1::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidOfInvestment)

和一个时尚的分配操作

pInv = ...     //make retVal point to the correct object

在这种情况下,可能需要创建一个空的 shared_ptr 并稍后进行分配?为什么不只要有资源(原始指针)就创建 shared_ptr 呢?

由于 Scott Meyers 在上一个示例中没有显示完整的赋值,我认为 shared_ptr 的赋值运算符被重载了,可以这样做:

pInv = new Investment;    // pInv will take charge of the pointer
                          // but meanwhile keep the delete function it already had

但我尝试了 boost 的实现,但它不能以这种方式工作。那么空 shared_ptr 是什么意思呢?

我几乎可以肯定我在这里遗漏了一些东西,请有人帮助我。

ps。更多关于 shared_ptr 的初始化和赋值

#include <boost/shared_ptr.hpp>

int main(int argc, char *argv[])
{
    boost::shared_ptr<int> ptr1(new int);
    boost::shared_ptr<int> ptr2;
    ptr2.reset(new int);
    boost::shared_ptr<int> ptr3 = new int;

    return 0;
}

这个例子不能被g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2和最新的boost编译:

sptr.cpp: In function ‘int main(int, char**)’:
sptr.cpp:8:39: error: conversion from ‘int*’ to non-scalar type ‘boost::shared_ptr<int>’    requested

【问题讨论】:

  • 我试图在这里弄清楚:ideone.com/BUjOwZ。我想不出一个解释。
  • 正如其他人所指出的,有很多理由需要一个空的 shared_ptr,就像你有空的原始指针一样。但真正的谜团是为什么 Scott 觉得需要自定义删除器。

标签: c++ c++11 shared-ptr effective-c++


【解决方案1】:

无需使用该 hack 来获取 null(空)shared_ptr。只需使用默认构造函数:

std::shared_ptr<Investment> pInv; // starts null

要分配指向shared_ptr 的指针,可以在构造时进行:

std::shared_ptr<Investment> pInt(new Investment);
// not allowed due to explicit annotation on constructor:
// std::shared_ptr<Investment> pInt = new Investment;

或者使用.reset()函数:

pInt.reset(new Investment);

该文章的作者可能打算提供自定义删除器 (getRidOfInvestment)。但是,当调用.reset() 或更改内部指针时,删除器函数会被重置。如果您想要自定义删除器,则必须在创建 shared_ptr 时将其传递给 .reset()

您可能希望使用自定义创建函数来使其更安全的一种模式:

class Investment {
protected:
  Investment();
  // ...
public:
  static shared_ptr<Investment> create();
};

shared_ptr<Investment> Investment::create() {
  return shared_ptr<Investment>(new Investment, getRidOfInvestment);
}

稍后:

shared_ptr<Investment> pInv = Investment::create();

这确保您始终将正确的析构函数附加到从Investments 创建的shared_ptrs。

【讨论】:

  • 问题中给出的示例,构造函数调用中出现空指针的原因是使用了自定义删除器。智能指针的构造函数没有只接受自定义删除器的版本,因此需要“hack”。
  • "std::shared_ptr pInt = 新投资;"无法编译
  • 哎呀,看起来它是一个显式构造函数。
  • 无论如何,因为当您重置指针时,自定义删除器也会被重置,对吧?那么带有自定义删除器的 null shared_ptr 在实际编程中完全没有意义,在这么好的书中有这样一个例子真是太奇怪了
  • 我以为我遗漏了什么,我拒绝相信 Scott 会弄错!但这是我能想到的唯一解释,+1
【解决方案2】:

具有空原始指针的原因相同 - 例如

说你有:

typedef std::tr1::shared_ptr<Investment> InvestmentPtr;
map<key,InvestmentPtr> portfolio;
...
get(mykey) {
  iterator it = portfolio.find(mykey);
  if (it == portfolio.end()) 
    return InvestmentPtr();
  else 
    return it->second;
  }
}

这允许你做:

InvestmentPtr p = get(key);
if (p) ...

【讨论】:

    【解决方案3】:

    您可能希望对象默认可构造的原因有很多。首先,您希望智能指针与原始指针尽可能相似,并且由于您可以说 int * p;(并获得未定义、未初始化的指针),您也可以说 shared_ptr&lt;int&gt; p; 并获得指针这并没有指向任何地方(但您可以使用 ! 对其进行测试)。

    最令人信服的原因之一可能是您可以使用shared_ptrs 制作容器,并且您可以填充容器而无需当场分配指针。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-04
      • 2018-01-07
      相关资源
      最近更新 更多