Зачем нужен нулевой shared_ptr и как его можно использовать? - PullRequest
9 голосов
/ 29 июля 2011

В Скотте Мейерсе 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, когда у вас есть ресурсы (необработанный указатель)?

Поскольку Скотт Мейерс не показал полное назначение в предыдущем примере, я подумал, что оператор присваивания 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 и последней версии:

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 ]

19 голосов
/ 29 июля 2011

Нет необходимости использовать этот хак для получения нулевого (пустого) 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 s.

7 голосов
/ 29 июля 2011

Это та же самая причина иметь нулевой необработанный указатель - например,

говорят, что у вас есть:

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 голосов
/ 29 июля 2011

Существует множество причин, по которым вам может понравиться возможность создания объектов по умолчанию.Прежде всего, вы хотите, чтобы умный указатель был максимально похож на необработанный указатель, и, поскольку вы можете сказать int * p; (и получить неопределенный неинициализированный указатель), вы также можете сказать shared_ptr<int> p; и получить указательэто никуда не указывает (но вы можете протестировать его с !).

Одна из наиболее веских причин, возможно, заключается в том, что вы можете сделать контейнеры с shared_ptr s, и вы можете заполнить контейнерыбез назначения пуантов тут же.

...