# Smart Pointer Parameters

### Problem #1

``````void f( shared_ptr<widget> w);
``````

``````struct shared_ptr_control_block {
some_atomic_counter_type reference_count;
// maybe other stuff....
};

template<typename T>
struct shared_ptr {
T *data;
shared_ptr_control_block *cntrl;
};
``````

``````void f(const std::shared_ptr<Widget>& w) {
w->foo();
}

void g() {
auto p = std::make_shared<Widget>(/*...*/);
f(p);
}
``````

### Problem #2

``````void f( Widget* w);              (a)
void f( Widget& w);              (b)
void f( unique_ptr<Widget> w);   (c)
void f( unique_ptr<Widget>& w);  (d)
void f( shared_ptr<Widget> w);   (e)
void f( shared_ptr<Widget>& w);  (f)
``````

(a) and (b): Prefer passing parameters by * or &

``````void f(Widget* w) {
w->foo();
}

void g() {
auto p = std::make_shared<Widget>(/*...*/);
f(p);
}
``````

(c) Passing unique_ptr by value means “sink.”

`unique_ptr`是不允许copy的，因此如果直接传递，编译器会报错，只能使用`std::move`

``````
void f(unique_ptr<Widget> w)) {
w->foo();
}

void g() {
auto p = std::make_unique<Widget>();
f(p); //error
}
```
```
``````
void f(unique_ptr<Widget> w)) {
w->foo();
}

void g() {
auto p = std::make_unique<Widget>();
f(std::move(p)); //good
// now p is nullptr
}
```
```

``````// Smelly 20th-century alternative

// Sweet self-documenting self-enforcing modern version (c)
void good_sink( unique_ptr<Widget> p );
``````

Guideline: Express a “sink” function using a by-value unique_ptr parameter.

(d) Passing unique_ptr by reference is for in/out unique_ptr parameters.

``````void f(std::unique_ptr<Widget>& w){
w.release();
}
void g() {
std::unique_ptr<Person> p = std::make_unique<Widget>("peter");
f(p);
// p is now nullptr
}
``````

Guideline: Use a non-const unique_ptr& parameter only to modify the unique_ptr.

Guideline: Don’t use a const unique_ptr& as a parameter; use widget* instead.

(e) Passing shared_ptr by value implies taking shared ownership.

``````
using namespace std;
void f(shared_ptr<Widget> w){
// ref count = 2
}
void g() {
shared_ptr<Widget> p =
make_shared<Widget>();
//ref count = 1
f(p);
// ref count = 1
}
```
```
``````
using namespace std;
void f(shared_ptr<Widget> w){
// ref count = 1
}
void g() {
shared_ptr<Widget> p =
make_shared<Widget>();
//ref count = 1
f(std::move(p));
// ref count = 0
//p is nullptr
}
```
```

(f) Passing shared_ptr& is useful for in/out shared_ptr manipulation.

(f)的情况和(d)类似，意思`w`将作为`in/out`参数，`g`可以mutate `w`，因此这不是一个很安全的做法。如果加上`const`，则`f`将表达另一个含义

``````using namespace std;
void f(const shared_ptr<Widget>& w){
// ref count = 1
}
void g() {
shared_ptr<Widget> p = make_shared<Widget>();
//ref count = 1
f(p);
// ref count = 1
//p is still valid
}
``````

Guideline: Use a non-const shared_ptr& parameter only to modify the shared_ptr. Use a const shared_ptr& as a parameter only if you’re not sure whether or not you’ll take a copy and share ownership; otherwise use widget* instead (or if not nullable, a widget&).