当对象表示硬件组件时,我应该使用指向对象或对象的指针吗?

Joã*_*lva 2 c++ new-operator v4l2 delete-operator

我有一个名为Camera的类,它在构造函数中打开带有v4l2_open等的摄像头.析构函数执行一些清理并使用v4l2_close关闭文件描述符.

当相机崩溃时,我所做的是删除对象,然后创建一个新对象:

Camera *camera = new Camera();
(...)
if (crash) {
  delete camera;
  camera = new Camera();
}
Run Code Online (Sandbox Code Playgroud)

这是C++中new/delete的正确用法吗?

5go*_*der 6

不,这里使用newdelete不保证.如果您的相机"变坏"并且您希望将其丢弃以支持新相机,只需指定一个新相机即可.

const std::string device {"/dev/cameras/front"};  // whatever
Camera camera {device};
// do something...
if (camera.bad())
  camera = Camera {device};  // replace by a new one
Run Code Online (Sandbox Code Playgroud)

您可能希望重载类的赋值运算符,Camera以使其工作.由于Camera该类是资源拥有的,因此它不应该是可复制的而是可移动的.我不知道你是如何与硬件交谈的,所以我做了下面的例子,但它应该给你正确的想法如何实现你的类型.

extern "C"
{
  // I have made these up...
  int camera_open(const char *);
  int camera_close(int);
}

class Camera
{

private:

  // Initially set to arbitrary nonsensical values.
  std::string device_ {};
  int fd_ {-1};

public:

  Camera() noexcept
  {
  }

  Camera(const std::string& device) : device_ {device}
  {
    this->open();
  }

  ~Camera() noexcept
  {
    try
      {
        this->close();
      }
    catch (const std::exception& e)
      {
        // Cannot throw from a destructor...
        std::cerr << e.what() << std::endl;
      }
  }

  Camera(const Camera&) = delete;  // not copy-constructible

  Camera(Camera&& other) : Camera {}
  {
    swap(*this, other);
  }

  Camera& operator=(const Camera&) = delete;  // not copy-assignable

  Camera&
  operator=(Camera&& other) noexcept
  {
    Camera tmp {};
    swap(*this, tmp);
    swap(*this, other);
    return *this;
  }

  friend void
  swap(Camera& first, Camera& second) noexcept
  {
    using std::swap;
    swap(first.device_, second.device_);
    swap(first.fd_, second.fd_);
  }

  void
  reopen()
  {
    this->close();
    this->open();
  }

  void
  open(const std::string& device = "")
  {
    if (this->fd_ >= 0)
      throw std::runtime_error {"camera already open"};
    if (!device.empty())
      this->device_ = device;
    if (this->device_.empty())
      throw std::runtime_error {"no associated device"};
    this->fd_ = camera_open(this->device_.c_str());
    if (this->fd_ < 0)
      throw std::runtime_error {"cannot open camera"};
  }

  void
  close()
  {
    if (this->fd_ >= 0)
      {
        if (camera_close(this->fd_) != 0)
          throw std::runtime_error {"cannot close camera"};
        this->fd_ = -1;
      }
  }
};
Run Code Online (Sandbox Code Playgroud)

但是你确定这首先是一个很好的设计决定吗?也许相机可以在必要时"重新加载"自己而不用这个实现细节完全打扰用户?

  • @TobiasKnauss我不同意这一点.类型本身的责任是在分配新值时释放它拥有的任何资源.这是RAII的重点,比必须记住在所有执行路径上手动调用清理函数要安全得多.考虑例如`std :: string`.如果为其分配一个新值,则在不再需要旧缓冲区时,字符串负责释放旧缓冲区.添加的代码演示了如何实现它. (3认同)
  • 我认为它依赖于类所需的内部功能,无论他是否只能分配一个新对象.如果摄像机需要清理并在删除时释放资源,他需要调用`camera.cleanup()`,或者使用指针并调用`delete camera`以便析构函数清理.无论如何,正如你所提到的,`reload()`会好得多. (2认同)