EMC++ Chapter 4: Smart Pointers
EMC++ Chapter 4: Smart Pointers
Smart Pointers
C++11 / C++14 smart pointer types
auto_ptr
unique_ptr
shared_ptr
weak_ptr
C++11 / C++14 smart pointer types
auto_ptr
C++98. Deprecated in C++11. Removed in C++17.
unique_ptr
C++11 replacement for auto_ptr. C++14 adds make_unique.
shared_ptr
C++11. Reference-counting.
weak_ptr
C++11. "Weak" references.
EMC++ Item 18
ptr to T
controlled object
of type T
std::unique_ptr<T, Deleter>
stack heap
ptr to T
controlled object
deleter
of type T
of type
Deleter
EMC++ Item 19
ptr to T
custom deleter?
ptr to controlled
object
Copying a std::shared_ptr
stack heap
ptr to T
ptr to default_delete<D>
control
block ptr to controlled
object of type D
“Shares ownership with”
#include <memory>
#include <vector>
std::shared_ptr<int> foo() {
auto elts = { 0,1,2,3,4 };
std::shared_ptr<Vec> pvec = std::make_shared<Vec>(elts);
return std::shared_ptr<int>(pvec, &(*pvec)[2]);
}
int main() {
std::shared_ptr<int> ptr = foo();
for (auto i = -2; i < 3; ++i) {
printf("%d\n", ptr.get()[i]);
}
}
“Shares ownership with”
#include <memory>
#include <vector>
std::shared_ptr<int> foo() {
auto elts = { 0,1,2,3,4 };
std::shared_ptr<Vec> pvec = std::make_shared<Vec>(elts);
return std::shared_ptr<int>(pvec, &(*pvec)[2]);
} Share ownership with pvec
but point to &(*pvec)[2]
int main() {
std::shared_ptr<int> ptr = foo();
for (auto i = -2; i < 3; ++i) {
printf("%d\n", ptr.get()[i]);
}
}
EMC++ Item 20
ptr to T
controlled object
Prefer std::make_unique
and std::make_shared
to direct use of new.
EMC++ Item 21
std::make_shared is an optimization
std::make_unique is not
http://channel9.msdn.com/Events/GoingNative/2013/Don-t-Help-the-Compiler
EMC++ Item 22
struct Widget::Impl {
...
class Widget { };
public:
Widget(); Widget::Widget()
~Widget(); : pImpl(new Impl) {}
private:
struct Impl; Widget::~Widget() {
Impl *pImpl; delete pImpl;
}; }
EMC++ Item 22: The Pimpl idiom
<<<Widget.h>>> <<<Widget.cpp>>>
If the class definition does not explicitly declare a copy constructor, one is declared
implicitly. If the class definition declares a move constructor or move assignment
operator, the implicitly declared copy constructor is defined as deleted; otherwise,
it is defined as defaulted. The latter case is deprecated if the class has a user-declared
copy assignment operator or a user-declared destructor.
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly
declared as defaulted if and only if
[Note: When the move constructor is not implicitly declared or explicitly supplied, expressions
that otherwise would have invoked the move constructor may instead invoke a copy constructor.
— end note]
Yup.
Sidebar: The Rule of Five
struct Widget {
Widget(Widget&&); // move construction
Widget(const Widget&); // copy construction
Widget& operator=(Widget&&); // move assignment
Widget& operator=(const Widget&); // copy assignment
~Widget(); // destructor
};
– If you declare any one of these, you should declare them all.
– Any of these may be declared =default or =delete
Sidebar: The Rule of Five
struct Widget {
Widget(Widget&&); // move construction
Widget(const Widget&); // copy construction
Widget& operator=(Widget&&); // move assignment
Widget& operator=(const Widget&); // copy assignment
~Widget(); // destructor
};
– If you declare any one of these, you should declare them all.
– Any of these may be declared =default or =delete, but...
– watch out for cases in which =default is not equivalent to {}
8.4.2 [dcl.fct.def.default] 4: A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.
8.5 [dcl.init] 7: If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided
default constructor.