void processWidget(std::shared_ptr<Widget> spw, int priority); void cusDel(Widget *ptr); // custom deleter // Here’s the exception-unsafe call: potential of resource leak. processWidget(std::shared_ptr<Widget>(new Widget, cusDel),computePriority() ); /* before the std::shared_ptr constructor, and if computePriority yields an exception, the dynamically allocated Widget will be leaked. Here the use of a custom deleter precludes use of std::make_shared, so the way to avoid the problem is to put the allocation of the Widget and the construction of the std::shared_ptr into their own statement */ // correct, but not optimal; see below std::shared_ptr<Widget> spw(new Widget, cusDel); processWidget(spw, computePriority()); /* The minor performance hitch is that in the exception-unsafe call, we’re passing an rvalue to processWidget */ // R-value processWidget(std::shared_ptr<Widget>(new Widget, cusDel),computePriority()); //but in the exception-safe call, we’re passing an lvalue: processWidget(spw, computePriority()); /* Because processWidget’s std::shared_ptr parameter is passed by value, construction from an rvalue entails only a move, while construction from an lvalue requires a
int main() { // Limitation 1: none of the make functions permit the specification of custom deleters. auto widgetDeleter = [](Widget* pw) { /* ... */ }; std::unique_ptr<Widget, decltype(widgetDeleter)> upw(new Widget(), widgetDeleter); std::shared_ptr<Widget> spw(new Widget(), widgetDeleter); // Limitation 2: within the make function, the perfect forwarding code uses // parentheses, not braces. The bad news of this is that if you want to // construct your pointed-to object using a braced initializer, you must use // new directly. { auto upv = std::make_unique<std::vector<int>>(10,20); auto spv = std::make_shared<std::vector<int>>(10,20); } { // create std::initializer_list auto initList = {10, 20}; // create std::vector using std::initializer_list ctor auto spv = std::make_shared<std::vector<int>>(initList); } // Limitation 3 (only for make_shared) auto pBigObj = // create very large std::make_shared<ReallyBigType>(); // object via // std::make_shared // create std::shared_ptrs and std::weak_ptrs to // large object, use them to work with it // final std::shared_ptr to object destroyed here, // but std::weak_ptrs to it remain // during this period, memory formerly occupied // by large object remains allocated // final std::weak_ptr to object destroyed here; // memory for control block and object is released std::shared_ptr<ReallyBigType> pBigObj(new ReallyBigType); // create very large // object via new // as before, create std::shared_ptrs and // std::weak_ptrs to object, use them with it // final std::shared_ptr to object destroyed here, // but std::weak_ptrs to it remain // memory for object is deallocated // during this period, only memory for // the control block remains allocated // final std::weak_ptr to object destroyed here; // memory for control block and object is released // Exception-unsafe call processWidget( // as before std::shared_ptr<Widget>(new Widget, cusDel), // potential computePriority() // resource ); // leak! // Exception-safe calls std::shared_ptr<Widget> spw(new Widget, cusDel); processWidget(spw, computePriority()); // correct, but not // optimal; see below processWidget(std::move(spw), // both efficient and computePriority()); // exception safe }