当使用“新”来初始化unique_ptr <FILE *,File :: Close>时,自定义删除器负责释放该内存吗?

Skr*_*rug 1 c++ unique-ptr c++11

智能指针对我来说是一个新概念。我一直在尝试使用带有自定义删除器(unique_ptr)的智能指针将File类包装在fopen_s和fclose周围。

以下是我的尝试。它可以成功编译,运行并生成一个名为“ text.txt”的文件,其中包含预期的内容“ Hello World”。

由于make_unique不适用于自定义删除程序,因此我必须在“ Open”函数中使用“ new”来初始化unique_ptr。由于我使用的是“ new”,我的自定义删除程序负责释放分配的内存吗?

我已逐步完成程序(VS2019)。File :: Close仅被调用一次。我希望当File:Open函数中的“ handle”超出范围时会被调用,但事实并非如此。此行为可能会受到对std :: move()的调用的影响。不确定如何进一步调查此处发生的情况。

#include <Windows.h>
#include <memory>
#include <string>
#include <map>

class File
{

private:

//functors - custom deleter
  struct Close { void operator()(FILE** _handle); };

//type definitions
  typedef std::unique_ptr<FILE*,File::Close> Handle;
  typedef std::map<std::string,Handle> HandleMap;

//static members
  static Handle& Open(std::string _name, std::string _mode);
  static HandleMap s_handle_map_;

//variables
  Handle& handle_;
  std::string name_;

public:

//functions
  File(std::string _name, std::string _mode);
  void Write(std::string _message);

};

File::HandleMap File::s_handle_map_;

File::File(std::string _name, std::string _mode)
:handle_(Open(_name,_mode)),
 name_(_name)
{
}

File::Handle& File::Open(std::string _name, std::string _mode)
{
  bool exist = s_handle_map_.count(_name) > 0;

  if (!exist)
  {
    Handle handle(new FILE*(nullptr));

    //open new file
    fopen_s(
      handle.get(),
      _name.c_str(),
      _mode.c_str()
    );

    //transfer ownership of handle
    s_handle_map_.emplace(
      _name,
      std::move(handle)
    );

  }

  return s_handle_map_[_name];
}

void File::Close::operator()(FILE** _handle)
{
  fclose(*_handle);
  *_handle = nullptr;

  //necessary?
  delete _handle;
  _handle = nullptr;
}

void File::Write(std::string _message)
{
  fprintf(*handle_, _message.c_str());
}

int WINAPI WinMain(HINSTANCE _instance, HINSTANCE _previous, LPSTR _cmd, int _show)
{
  File file("test.txt","w");
  file.Write("Hello World\n");
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*phe 5

每当您想到时unique_ptr<FILE*, ...>,请深呼吸,等待一分钟,然后继续操作fstream

以下代码执行相同的操作,但是依赖于经过验证和良好测试的C ++标准库。fstream具有您期望的所有功能,包括在不再需要它们时自动关闭:

int WINAPI WinMain(HINSTANCE _instance, HINSTANCE _previous, LPSTR _cmd, int _show)
{
  fstream file("test.txt", fstream::out);
  file << "Hello World\n";
  return 0;
}  
Run Code Online (Sandbox Code Playgroud)

您完全不必担心内存管理。

现在,概括您的问题:

  • 如果您unique_ptr<T,D>基于new T指针创建自己,则自定义删除器D将负责delete T。否则,您将泄漏内存(示例)。
  • 因此,更好的方法是继续使用默认的删除器,并确保T的析构函数将清除或关闭所需的任何东西。
  • 而且,一旦您选择了默认的删除器,最好的办法 make_unique就是比新方法具有一些优势(请参见此处的原因