为什么需要null shared_ptr以及如何使用它?

时间:2011-07-28 21:45:38

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

在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

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

由于Scott Meyers在前面的例子中没有显示完整的赋值,我认为shared_ptr的assign运算符是重载的,可以这样做:

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

但是我尝试使用 boost 的实现它不会这样工作。那么null 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 和最新的提升编译:

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

3 个答案:

答案 0 :(得分:19)

没有必要使用该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()时,或者在更改内部指针时,将重置删除函数。如果您想要自定义删除工具,则必须在创建.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_ptr s创建的Investment相关联的正确析构函数。

答案 1 :(得分: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) ...

答案 2 :(得分:2)

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

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