C++:智能指针(一)

正文

关于这个例子:

#include <iostream>
#include <memory>
#include <string>

std::unique_ptr<std::string> demo(const char *s) {
    std::unique_ptr<std::string> temp(new std::string(s));
    return temp;
}

int main() {
    // 调用demo函数,返回一个unique_ptr<string>,并将其赋值给ps
    std::unique_ptr<std::string> ps;
    ps = demo("Uniquely special");

    // 输出ps所指向的字符串内容
    std::cout << *ps << std::endl;

    return 0;
}

我们很容易理解,智能指针来源于模板类,对于上面的 demo(),它返回了一个对象 temp。按照一般认知,在不考虑前面讨论的返回值优化的前提下,demo() 在返回前会移动构造创建一个临时栈外的对象,然后通过这个对象再移动赋值给 ps,然后析构掉 temp,这个过程依赖于移动赋值函数。智能指针之所以智能,就是做了一些特定的设计:

#ifdef _LIBCPP_CXX03_LANG
  unique_ptr(unique_ptr const&) = delete;
  unique_ptr& operator=(unique_ptr const&) = delete;
#endif
...

在头文件 memory 中,可以看到上面的代码禁止了复制构造函数和复制赋值构造函数,因此上面的提到的过程就会发生。但是这会导致空指针异常吗?按照之前的经验,返回的对象 temp 会被销毁,从而导致 ps 对象是空的。

这时候,就要了解智能指针设计的精妙了:

template <class _Up, class _Ep,
      class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>,
      class = _EnableIfDeleterAssignable<_Ep>
  >
  _LIBCPP_INLINE_VISIBILITY
  unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT {
    reset(__u.release());
    __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter());
    return *this;
  }
...

**尽管智能指针禁止了复制构造函数和复制赋值构造函数,但是提供了移动赋值运算符重载函数。**这将会在赋值的时候,将右值的资源转让给左值。因此上面的程序是没有任何错误与风险的。

再来看看关于智能指针的一个程序:

#include <iostream>
#include <memory>
#include <vector>

std::unique_ptr<int> make_int(int n) {
    return std::unique_ptr<int>(new int(n));
}

void show(std::unique_ptr<int> &pi) {
    std::cout << *pi << ' ';
}

int main() {
    // 创建一个包含动态分配整数的 unique_ptr 向量
    std::vector<std::unique_ptr<int>> vp(10);
    for (int i = 0; i < vp.size(); ++i) {
        // 通过 make_int 函数创建动态分配的整数,并将其存储在向量中
        vp[i] = make_int(rand() % 1000);
    }

    // 使用 for_each 遍历向量,并调用 show 函数显示每个整数
    for (auto& ptr : vp) {
        show(ptr);
    }

    return 0;
}

在给show()函数传递参数时,如果按值而不是按引用传递unique_ptr对象,会导致编译器尝试复制unique_ptr对象,这是不允许的,因为unique_ptr禁止了复制构造函数。因此,如果按值传递unique_ptr对象给show()函数,编译器将发出错误提示。

另外,for_each()函数中的lambda表达式会将vp中的每个元素传递给show()函数,而lambda表达式默认情况下是按值捕获参数的。因此,如果show()函数接受的参数是按值而不是按引用传递的,那么for_each()语句将会产生编译错误,因为它会尝试复制构造unique_ptr对象。

为了解决这个问题,可以将show()函数的参数声明为const std::unique_ptr<int>&,以便按引用传递参数,或者使用std::move()unique_ptr对象作为右值传递给show()函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值