概述
使用智能指针的目的之一,就是减少对象的拷贝。要禁止拷贝和赋值
智能指针代码1
template <typename T>
class smart_ptr {
…
smart_ptr(smart_ptr& other)
{
ptr_ = other.release();
}
smart_ptr& operator=(smart_ptr& rhs)
{
smart_ptr(rhs).swap(*this);
return *this;
}
…
T* release()
{
T* ptr = ptr_;
ptr_ = nullptr;
return ptr;
}
void swap(smart_ptr& rhs)
{
using std::swap;
swap(ptr_, rhs.ptr_);
}
…
};
在拷贝构造函数中,通过调用 other 的 release 方法来释放它对指针的所有权
在赋值函数中,则通过拷贝构造产生一个临时对象并调用 swap 来交换对指针的所有权
同时,这里一个大问题。如果不小心other把它传递给另一个smart_ptr,就不再拥有这个对象
“移动”指针
template <typename T>
class smart_ptr {
…
smart_ptr(smart_ptr&& other)
{
ptr_ = other.release();
}
smart_ptr& operator=(smart_ptr rhs)
{
rhs.swap(*this);
return *this;
}
…
};
把拷贝构造函数中的参数类型 smart_ptr& 改成了 smart_ptr&&;现在它成了移动构造函数
- 输入一个即将销毁的右值,这样转移指针所有权完成移动
把赋值函数中的参数类型 smart_ptr& 改成了 smart_ptr,在构造参数时直接生成新的智能指针,从而不再需要在函数体中构造临时对象
现在赋值函数的行为是移动还是拷贝,完全依赖于构造参数时走的是移动构造还是拷贝构造
-
operator=()的参数在接收参数的时候,会调用构造函数,如果调用的是拷贝构造,那赋值操作就是拷贝
-
如果调用的是移动构造,那么赋值操作就是移动
根据 C++ 的规则,如果我提供了移动构造函数而没有手动提供拷贝构造函数,那后者自动被禁用
通用构造函数
template <typename U>
smart_ptr(smart_ptr<U>&& other)
{
ptr_ = other.release();
}
增加新的构造函数,但是这个构造函数不被编译器看成移动构造函数,因而不能自动触发删除拷贝构造函数行为
详细代码
#include <utility> // std::swap
class shared_count {
public:
shared_count() noexcept
: count_(1) {}
void add_count() noexcept
{
++count_;
}
long reduce_count() noexcept
{
return --count_;
}
long get_count() const noexcept
{
return count_;
}
private:
long count_;
};
template <typename T>
class smart_ptr {
public:
template <typename U>
friend class smart_ptr;
explicit smart_ptr(T* ptr = nullptr)
: ptr_(ptr)
{
if (ptr) {
shared_count_ =
new shared_count();
}
}
~smart_ptr()
{
if (ptr_ &&
!shared_count_
->reduce_count()) {
delete ptr_;
delete shared_count_;
}
}
smart_ptr(const smart_ptr& other)
{
ptr_ = other.ptr_;
if (ptr_) {
other.shared_count_
->add_count();
shared_count_ =
other.shared_count_;
}
}
template <typename U>
smart_ptr(const smart_ptr<U>& other) noexcept
{
ptr_ = other.ptr_;
if (ptr_) {
other.shared_count_->add_count();
shared_count_ = other.shared_count_;
}
}
template <typename U>
smart_ptr(smart_ptr<U>&& other) noexcept
{
ptr_ = other.ptr_;
if (ptr_) {
shared_count_ =
other.shared_count_;
other.ptr_ = nullptr;
}
}
template <typename U>
smart_ptr(const smart_ptr<U>& other,
T* ptr) noexcept
{
ptr_ = ptr;
if (ptr_) {
other.shared_count_
->add_count();
shared_count_ =
other.shared_count_;
}
}
smart_ptr&
operator=(smart_ptr rhs) noexcept
{
// 掏空rhs。this原本持有的内容立即释放
// @todo
rhs.swap(*this);
return *this;
}
T* get() const noexcept
{
return ptr_;
}
long use_count() const noexcept
{
if (ptr_) {
return shared_count_
->get_count();
} else {
return 0;
}
}
void swap(smart_ptr& rhs) noexcept
{
using std::swap;
swap(ptr_, rhs.ptr_);
swap(shared_count_,
rhs.shared_count_);
}
T& operator*() const noexcept
{
return *ptr_;
}
T* operator->() const noexcept
{
return ptr_;
}
operator bool() const noexcept
{
return ptr_;
}
private:
T* ptr_;
shared_count* shared_count_;
};
template <typename T>
void swap(smart_ptr<T>& lhs,
smart_ptr<T>& rhs) noexcept
{
lhs.swap(rhs);
}
template <typename T, typename U>
smart_ptr<T> static_pointer_cast(
const smart_ptr<U>& other) noexcept
{
T* ptr = static_cast<T*>(other.get());
return smart_ptr<T>(other, ptr);
}
template <typename T, typename U>
smart_ptr<T> reinterpret_pointer_cast(
const smart_ptr<U>& other) noexcept
{
T* ptr = reinterpret_cast<T*>(other.get());
return smart_ptr<T>(other, ptr);
}
template <typename T, typename U>
smart_ptr<T> const_pointer_cast(
const smart_ptr<U>& other) noexcept
{
T* ptr = const_cast<T*>(other.get());
return smart_ptr<T>(other, ptr);
}
template <typename T, typename U>
smart_ptr<T> dynamic_pointer_cast(
const smart_ptr<U>& other) noexcept
{
T* ptr = dynamic_cast<T*>(other.get());
return smart_ptr<T>(other, ptr);
}