9

在 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的实现,但它不能以这种方式工作。那么拥有 null shared_ptr 有什么意义呢?

我几乎可以肯定我在这里遗漏了一些东西,请有人帮我解决这个问题。

附言。有关 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
4

3 回答 3

22

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

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

要将指针分配给 a 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()被调用时会被重置,或者当内部指针被更改时。如果你想要一个自定义删除器,你必须.reset()在创建shared_ptr.

您可能想要使用的一种模式来使其更加安全,这是自定义创建函数:

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();

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

于 2011-07-28T21:48:37.563 回答
7

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

说你有:

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) ...
于 2011-07-28T21:53:07.603 回答
2

您可能希望对象默认可构造的原因有很多。首先,您希望智能指针与原始指针尽可能相似,并且由于您可以说int * p;(并获得一个未定义的、未初始化的指针),您也可以说shared_ptr<int> p;并获得一个不指向任何地方的指针(但你可以用 来测试它!)。

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

于 2011-07-28T21:49:05.777 回答