In Scott Meyers's Effective C++, item 18 Make interfaces easy to use correctly and hard to use incorrectly, he mentioned the null shared_ptr:
std::tr1::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidOfInvestment)
and a vogue assignment operation
pInv = ... //make retVal point to the correct object
In which case one may need to create a null shared_ptr and do assignment later? Why not just create the shared_ptr whenever you have the resources (raw pointer)?
Since Scott Meyers did not show the complete assignment in the previous example, I thought the shared_ptr's assign operator is overloaded that one can do this:
pInv = new Investment; // pInv will take charge of the pointer
// but meanwhile keep the delete function it already had
But I tried with boost's implementation it doesn't work this way. Then what is the sense to have null shared_ptr?
I am almost sure that I am missing something here, someone help me out of it please.
ps. more about the initialization and assignment of a 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;
}
this example can not be compiled by g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 and the latest 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
There is no need to use that hack to get a null (empty) shared_ptr
. Simply use the default constructor:
std::shared_ptr<Investment> pInv; // starts null
To assign a pointer to a shared_ptr
, either do it at construction time:
std::shared_ptr<Investment> pInt(new Investment);
// not allowed due to explicit annotation on constructor:
// std::shared_ptr<Investment> pInt = new Investment;
Or use the .reset()
function:
pInt.reset(new Investment);
It's possible that the author of that article may have intended to provide a custom deleter (getRidOfInvestment
). However, the deleter function is reset when .reset()
is called, or when otherwise the inner pointer is changed. If you want a custom deleter, you must pass it to .reset()
upon creation of the shared_ptr
.
One pattern you might want to use to make this more foolproof is a custom creation function:
class Investment {
protected:
Investment();
// ...
public:
static shared_ptr<Investment> create();
};
shared_ptr<Investment> Investment::create() {
return shared_ptr<Investment>(new Investment, getRidOfInvestment);
}
Later:
shared_ptr<Investment> pInv = Investment::create();
This ensures you will always have the correct destructor function attached to the shared_ptr
s created from Investment
s.
It's the same reason to have a null raw pointer - e.g.
say you have:
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;
}
}
This allows you to do:
InvestmentPtr p = get(key);
if (p) ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With