移动带有文件描述符的对象

Gre*_*ers 5 c++

例如,我有一个类Foo,定义如下:

class Foo {
public:
  Foo(int i) {
    valid = false;
    char devname[] = "/dev/device0";
    sprintf(devname, "/dev/device%d", i);
    fd = open(devname, O_RDWR);
    if (fd > 0) {
      valid = true;
    }

  ~Foo() {
    if (valid) {
      close(fd);
    }
  }

  bool valid;
private:
  int fd;
};
Run Code Online (Sandbox Code Playgroud)

我有另一个类,比如Bar,定义如下:

class Bar {
public:
  Bar() {
    for (int i = 0; i < 4; i++) {
      Foo foo(i);
      if (foo.valid) {
        vector_of_foos.push_back(foo);
      }
    }
  }

  std::vector<Foo> vector_of_foos;
};
Run Code Online (Sandbox Code Playgroud)

这样做的问题是push_back制作了 Foo 对象的副本,该对象复制了该fd属性。然后Foo调用原始对象的析构函数,关闭fd指向的文件,呈现fd无效。

不幸的是我无法使用,emplace_back因为我需要Foo对象添加到向量之前实例化它,vector_of_foos以便我可以检查valid属性。

我也尝试过使用,std::move但是Foo一旦超出范围关闭文件,它仍然会调用原始对象的析构函数。

管理这样的资源的推荐方法是什么?我应该使用智能指针数组吗?我vector_of_foos应该在std::vector<Foo *>那里维护一个Foo我动态分配的指针向量吗?

Rem*_*eau 3

Foo需要一个复制构造函数和复制赋值运算符,以便它可以复制源对象(或者,您需要dup()它们,以便对象根本无法复制,只能移动)。fddeleteFoo

实现移动语义时,将fd值从移出对象移动到移至对象后,您需要更新移出对象,使其fd不再引用有效的文件描述符。只需将其设置为 -1,即错误open()dup()返回。

valid你根本不需要你的会员。如果它与您的fd.

尝试更多类似这样的事情:

class Foo {
public:
  Foo(int i) {
    std::string devname = "/dev/device" + std::to_string(i);
    fd = open(devname.c_str(), O_RDWR);
  }

  Foo(const Foo &src) {
    fd = dup(src.fd);
  }
  // or: Foo(const Foo &) = delete;

  Foo(Foo &&src) : fd(-1) {
    src.swap(*this);
  }

  ~Foo() {
    if (fd != -1) {
      close(fd);
    }
  }

  bool valid() const {
    return (fd != -1); 
  }

  Foo& operator=(Foo rhs) {
    rhs.swap(*this);
    return *this;
  }
  // optional: Foo& operator=(const Foo &) = delete;

  void swap(Foo &other) {
    std::swap(fd, other.fd);
  }

private:
  int fd;
};
Run Code Online (Sandbox Code Playgroud)