带有自定义指针类型的unique_ptr:*get()和operator*()给出不同的输出

Tom*_*pen 2 c++ c++11

根据cppreference调用std::unique_ptr::operator*()相当于调用*(std::unique_ptr::get()).

但是我对两个电话都有不同的结果.这是我的代码:

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

#include <fcntl.h>
#include <unistd.h>

struct file_descriptor
{
private:
  struct closer;

public:
  typedef int handle_type;
  typedef closer closer_type;

  constexpr static handle_type kInvalidHandle = -1;

public:
  file_descriptor(int handle = kInvalidHandle) : handle_{ handle } { }
  file_descriptor(std::nullptr_t) : file_descriptor{ } { }

  operator int&() { return handle_; }
  operator int() const { return handle_; }

  int& operator*() { return static_cast<int&>(*this); }
  int operator*() const { return static_cast<int>(*this); }

  bool operator==(const file_descriptor& other) const
  { return (handle_ == other.handle_); }

  bool operator!=(const file_descriptor& other) const
  { return !(*this == other); }

private:
  struct closer
  {
    typedef file_descriptor pointer;

    void operator()(pointer handle) const
    { ::close(*handle); }
  };

  int handle_;
};

using unique_file_ptr = std::unique_ptr<typename file_descriptor::handle_type,
                                        typename file_descriptor::closer_type>;

unique_file_ptr managed_open(const std::string& path)
{
  return { ::open(path.c_str(), O_RDWR), { } };
}

int main(int, char**)
{
  auto handle = managed_open("/dev/random");
  std::cout << "*handle      : " << *handle << std::endl;
  std::cout << "*handle.get(): " << *handle.get() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我的输出(这里的实时输出):

*handle      : 4198400
*handle.get(): 3
Run Code Online (Sandbox Code Playgroud)

请注意,*handle.get()返回正确的值,而*handle不是.

为什么我会得到不同的结果?

Igo*_*nik 6

这是发生了什么.unique_ptr<T, D>::get()返回D::pointer- 在您的情况下,file_descriptorint句柄构造临时.然后它operator*调用它operator int&返回一个handle_存储在临时内部的引用.

*handle.get()直接调用时,int&它产生的引用在临时死亡之前使用.

但是当你拨打电话时*handle,你handle.operator*()会拨打电话handle.get().的实施operator*,什么东西都扩大了,变成是这样的:

int& operator*() {
  file_descriptor temp(internal_pointer_);
  int& result = temp.handle_;
  return result;
}
Run Code Online (Sandbox Code Playgroud)

该函数返回对临时成员的引用.那个临时模块在关闭括号中死亡,并且引用变得悬空,于是程序显示出在生命周期结束后访问对象而触发的未定义行为.